home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2009 February
/
PCWFEB09.iso
/
Software
/
Linux
/
Kubuntu 8.10
/
kubuntu-8.10-desktop-i386.iso
/
casper
/
filesystem.squashfs
/
usr
/
bin
/
foomatic-configure
< prev
next >
Wrap
Text File
|
2008-08-19
|
137KB
|
4,507 lines
#!/usr/bin/perl -w
use strict; # -*- perl -*-
# This is foomatic-configure, a program to establish and configure
# print queues, drivers, spoolers, etc using the foomatic database and
# companion filters.
# It also comprises half of a programatic API for user tools: you can
# learn and control everything about the static properties of print
# queues here. With the sister program foomatic-printjob, you can do
# everything related to print queue dynamic state: submit jobs, and
# query, cancel, reorder, and redirect them.
use Foomatic::Defaults;
use Foomatic::DB;
use Data::Dumper;
# Connect syntax:
#
# This differs a tad from CUPS's, partly because everything is
# supposed to be a file, and CUPS doesn't entirely reflect that.
# But I'm not really very particular...
#
# If a certain URI is not supported by all the spoolers, the spoolers
# which support it are listed in parantheses, "direct" means direct,
# spooler-less printing.
#
# usb:/path/device # Local USB printer
# usb://make/model?serial=xxx # Printer-bound USB connection (CUPS)
# parallel:/path/device # Local parallel printer
# serial:/path/device # Local serial printer
# file:/path/file # includes usb, lp, named pipes, other
# hp:/bus/model?serial=xxx # HPLIP print queue (hpinkjet.sf.net)
# hpfax:/bus/model?serial=xxx # HPLIP fax queue (hpinkjet.sf.net)
# ptal:/provider:bus:name # HPOJ MLC protocol (hpoj.sf.net,obsolete)
# mtink:/path/device # Epson inkjet through mtink daemon
# # (for ink level monitoring when printing,
# # http://xwtools.automatix.de/)
# lpd://host/queue # LPD protocol
# lpd://host # LPD protocol (default queue, CUPS only)
# socket://host:port # TCP aka appsocket
# socket://host # TCP aka appsocket (port 9100)
# ncp://user:pass@host/queue # Netware (LPD, LPRng, direct)
# smb://user:pass@wgrp/host/queue # Windows (CUPS, PPR, LPD, LPRng, direct)
# stdout # Standard output (direct)
# postpipe:"<command line>" # Free-formed backend command line
# # (LPD, LPRng, direct)
#
# Read out the program name with which we were called, but discard the path
$0 =~ m!/([^/]+)\s*$!;
my $progname = ($1 || $0);
my $debug = 0;
# We use the library Getopt::Long here, so that we can have more than
# one "-o" option on one command line.
my($opt_q, $opt_f, $opt_w, $opt_n, $opt_N, $opt_L, $opt_ppd,
$opt_d, $opt_p, $opt_s, $opt_C, $opt_R, $opt_D, $opt_Q, $opt_P,
$opt_O, $opt_X, $opt_c, @opt_o, $opt_r, $opt_dd, $opt_nodd,
$opt_att, $opt_delay, $opt_h);
use Getopt::Long;
Getopt::Long::Configure("no_ignore_case");
GetOptions("q" => \$opt_q, # Quiet, non-interactive operation
"f" => \$opt_f, # Force rebuild of PPD from database
"w" => \$opt_w, # Cut GUI strings in the PPD to 39
# characters (for CUPS Windows driver)
"n=s" => \$opt_n, # queue Name
"N=s" => \$opt_N, # human-readable Name (Model,
# Description)
"L=s" => \$opt_L, # Location
"ppd=s" => \$opt_ppd, # PPD file
"d=s" => \$opt_d, # Driver
"p=s" => \$opt_p, # Printer
"s=s" => \$opt_s, # Spooler
"C" => \$opt_C, # Copy queue
"R" => \$opt_R, # Remove queue
"D" => \$opt_D, # set Default queue
"Q" => \$opt_Q, # Query queue info
"P" => \$opt_P, # Perl queue/printer/driver info output
"O" => \$opt_O, # get printer support Overview
"X" => \$opt_X, # query XML printer/driver/combo info
"c=s" => \$opt_c, # printer Connection type
"o=s" => \@opt_o, # default printing Options
"r" => \$opt_r, # list Remote queues
"backend-dont-disable=s" => \$opt_dd, # Do not disable CUPS
# backends
"backend-attempts=s" => \$opt_att, # Try that often when backend
# fails
"backend-delay=s" => \$opt_delay, # Delay in seconds between
# retries of failed backend
"h" => \$opt_h, # Help!
"help"=> \$opt_h) || help();
help() if $opt_h;
my $db = new Foomatic::DB;
overview() if $opt_O;
get_xml() if $opt_X;
my $force = ($opt_f ? 1 : 0);
my $shortgui = ($opt_w ? 1 : 0);
my $in_config = {'queue' => $opt_n,
'desc' => $opt_N,
'loc' => $opt_L,
'ppdfile' => $opt_ppd,
'driver' => $opt_d,
'printer' => $opt_p,
'spooler' => $opt_s,
'connect' => $opt_c,
'options' => \@opt_o,
'force' => $force,
'shortgui' => $shortgui,
'dd' => $opt_dd,
'att' => $opt_att,
'delay' => $opt_delay,
'foomatic' => 1};
# If description and location contain only whitespace, use an empty string
# instead
if ((defined($in_config->{'desc'})) && ($in_config->{'desc'} =~ m!^\s*$!)) {
$in_config->{'desc'} = "";
}
if ((defined($in_config->{'loc'})) && ($in_config->{'loc'} =~ m!^\s*$!)) {
$in_config->{'loc'} = "";
}
my $action = ($opt_R ? 'delete' : 'configure');
$action = ($opt_D ? 'default' : $action);
$action = ($opt_Q ? 'query' : $action);
$action = ($opt_P ? 'query' : $action);
my $procs = { 'lpd' => { 'delete' => \&delete_lpd,
'configure' => \&setup_lpd,
'default' => \&default_lpd,
'query' => \&query_lpd },
'lprng'=>{ 'delete' => \&delete_lpd,
'query' => \&query_lpd,
'default' => \&default_lprng,
'configure' => \&setup_lpd },
'cups' =>{ 'delete' => \&delete_cups,
'query' => \&query_cups,
'default' => \&default_cups,
'configure' => \&setup_cups },
'pdq' =>{ 'delete' => \&delete_pdq,
'query' => \&query_pdq,
'default' => \&default_pdq,
'configure' => \&setup_pdq },
'ppr' =>{ 'delete' => \&delete_ppr,
'query' => \&query_ppr,
'default' => \&default_ppr,
'configure' => \&setup_ppr },
'direct'=>{'delete' => \&delete_direct,
'query' => \&query_direct,
'default' => \&default_direct,
'configure' => \&setup_direct } };
if (!($opt_Q or $opt_P or defined($in_config->{'queue'}))) {
# No queue manipulation without knowing the name of the queue
print STDERR "You must specify a queue name with -n!\n";
help();
exit 1;
}
if (!defined($in_config->{'spooler'})) {
my $takenfromconfigfile = 0;
# Personal default spooler
my $s;
if (($> != 0) && (-f "$ENV{'HOME'}/.defaultspooler")) {
$s = `cat $ENV{'HOME'}/.defaultspooler`;
chomp $s;
$takenfromconfigfile = 1;
}
# System default spooler
if ((!defined($s)) && (-f "$sysdeps->{'foo-etc'}/defaultspooler")) {
$s = `cat $sysdeps->{'foo-etc'}/defaultspooler`;
chomp $s;
$takenfromconfigfile = 1;
}
if (!defined($s)) {
$s = detect_spooler();
}
die "Unable to identify spooler, please specify with -s\n"
unless $s;
if ((!$opt_q) && (!$takenfromconfigfile)) {
print STDERR "You appear to be using $s. Correct? ";
my $yn = <STDIN>;
die "\n" if ($yn !~ m!^y!i);
}
$in_config->{'spooler'} = $s;
}
if ($in_config->{'printer'}) {
# If the user supplies an old numerical printer ID, translate it to
# a new clear-text ID
$in_config->{'printer'} =
Foomatic::DB::translate_printer_id($in_config->{'printer'});
}
# Call proper proc
&{$procs->{$in_config->{'spooler'}}{$action}}($in_config);
exit(0);
# Common parts for queue creation/modification functions
sub getoldqueuedata {
my ($config, $reconf) = @_;
my ($sourcespooler, $sourcequeue, $olddatablob, $beh);
# Copy a queue
if ($opt_C) {
if ($#ARGV == 0) { # 1 argument -> queue from same spooler
$sourcespooler = $config->{'spooler'};
$sourcequeue = $ARGV[0];
} elsif ($#ARGV == 1) { # 2 arguments -> queue from given spooler
$sourcespooler = $ARGV[0];
$sourcequeue = $ARGV[1];
} else {
die "Unsufficient options to copy a queue, " .
"try \"$progname -h\"!\n";
}
# Read data from source queue
if (!($olddatablob = load_datablob($sourcespooler, $sourcequeue))) {
# It is not possible to copy the given source queue
die "The source queue $sourcequeue does not exist " .
"or is corrupted!\n";
}
# PPD file of the source queue, if it exists, and if the user
# does not insist on using another PPD file, we must copy it
my $sourceppd = $olddatablob->{'ppdfile'};
if ((-r $sourceppd) && (!$config->{'ppdfile'})) {
$config->{'ppdfile'} = $sourceppd;
}
# Stuff data into the $config structure, all items must be defined,
# so that an old queue gets overwritten
if ($olddatablob->{'queuedata'}) {
my $i;
for $i (('desc', 'loc', 'printer', 'driver', 'connect',
'ppdfile', 'dd', 'att', 'delay')) {
if (!defined($config->{$i})) {
if ($olddatablob->{'queuedata'}{$i}){
$config->{$i} = $olddatablob->{'queuedata'}{$i};
} elsif ($i eq 'dd') {
$config->{$i} = 0;
} elsif ($i eq 'att') {
$config->{$i} = 1;
} elsif ($i eq 'delay') {
$config->{$i} = 30;
} else {
$config->{$i} = "";
}
}
}
# Check consistency of the printer/driver settings
if ((($config->{'driver'} eq "") ||
($config->{'driver'} eq "raw") || # No new driver, printer,
($config->{'printer'} eq "")) && # PPD file
($config->{'ppdfile'} eq "") &&
((!defined($olddatablob->{'args'})) || # No existing options
($#{$olddatablob->{'args'}} < 0))) { # -> source queue raw
$config->{'driver'} = "raw";
$config->{'printer'} = undef;
}
# We do not need the queue data block any more
delete($olddatablob->{'queuedata'});
} else {
# No Foomatic/PPD data
$olddatablob = undef;
}
} else {
# Load the datablob of the former configuration
if ($reconf) {
if ($olddatablob = load_datablob($config->{'spooler'},
$config->{'queue'})) {
# If the user has supplied only a printer or only a driver
# fill in the second of the two fields in $config
if ((!$config->{'ppdfile'}) &&
($olddatablob->{'queuedata'}{'foomatic'})) {
if ((!$config->{'driver'}) && ($config->{'printer'})) {
$config->{'driver'} = $olddatablob->{'driver'};
}
if ((!$config->{'printer'}) && ($config->{'driver'})) {
$config->{'printer'} = $olddatablob->{'id'};
}
}
# Extract URI and backend error handling data
if ($config->{'spooler'} eq "cups") {
$beh->{'uri'} = $olddatablob->{'queuedata'}{'connect'};
$beh->{'dd'} = $olddatablob->{'queuedata'}{'dd'};
$beh->{'att'} = $olddatablob->{'queuedata'}{'att'};
$beh->{'delay'} = $olddatablob->{'queuedata'}{'delay'};
}
# We do not need the queue data block here
delete($olddatablob->{'queuedata'});
} else {
$olddatablob = undef;
}
}
}
# If the user does not supply info about his printer and/or driver
# and the queue did not exist before we assume that he wants to set up a
# raw queue. To make a raw queue out of a formerly filtered one, one
# has to use the driver name "raw".
$config->{'driver'} = "" if not defined $config->{'driver'};
$config->{'printer'} = "" if not defined $config->{'printer'};
$config->{'ppdfile'} = "" if not defined $config->{'ppdfile'};
my $nodriver = (((!$config->{'driver'}) && (!$config->{'printer'}) &&
(!$config->{'ppdfile'})) ||
($config->{'driver'} eq "raw"));
# Set to 1 when we retrieve a data set from the Foomatic database
my $newfoomaticdata = 0;
if ($nodriver) {
if ($olddatablob) {
if ($config->{'driver'} ne "raw") {
# We couldn't determine a certain driver, probably we had a
# native PostScript PPD file
$db->{'dat'} = $olddatablob;
} else {
# For a raw queue overtake at least the $postpipe
if (defined($olddatablob->{'postpipe'})) {
$db->{'dat'}{'postpipe'} = $olddatablob->{'postpipe'};
}
}
}
} elsif ($config->{'ppdfile'}) {
if (! -r $config->{'ppdfile'}) {
die "The PPD file \'$config->{'ppdfile'}\' does not exist or is " .
"readable.\n";
}
# Load the data from the PPD file
$db->getdatfromppd($config->{'ppdfile'});
# Overtake the former default settings
if ($olddatablob) {overtake_defaults($olddatablob)};
# Overtake the former $postpipe
if (defined($olddatablob->{'postpipe'})) {
$db->{'dat'}{'postpipe'} = $olddatablob->{'postpipe'};
}
} else {
if (($olddatablob) &&
($olddatablob->{'driver'} eq $config->{'driver'}) &&
($olddatablob->{'id'} eq $config->{'printer'}) &&
(!$config->{'force'})) {
# Overtake data from the former configuration
$db->{'dat'} = $olddatablob;
} else {
# Retrieve data from the Foomatic database
if (!$config->{'driver'}) {
die "You also need to specify a driver with \"-d\"!\n";
}
if (!$config->{'printer'}) {
die "You also need to specify a printer with \"-p\"!\n";
}
# The printer is supported by the chosen driver? If yes, load
# its data
my $possible = $db->getdat($config->{'driver'},
$config->{'printer'});
die "That printer and driver combination is not possible.\n"
if (!$possible);
die "There is neither a custom PPD file nor the driver database entry contains sufficient data to build a PPD file.\n"
if (!$db->{'dat'}{'cmd'}) && (!$db->{'dat'}{'ppdfile'});
$newfoomaticdata = 1;
# Overtake the former default settings
if ($olddatablob) {overtake_defaults($olddatablob)};
# Overtake the former $postpipe
if (defined($olddatablob->{'postpipe'})) {
$db->{'dat'}{'postpipe'} = $olddatablob->{'postpipe'};
}
}
}
# When we have no arguments in the current configuration, we must have
# a raw queue
my $rawqueue = ((!defined($db->{'dat'}{'args'})) ||
($#{$db->{'dat'}{'args'}} < 0));
# Set the default printing options supplied on the command line
if (!$rawqueue) {
set_default_options($config, $db->{'dat'});
}
# Printer model name (for comment field of the queue configuration)
my ($make, $model, $makemodel);
if (defined($db->{'dat'})) {
$make = $db->{'dat'}{'make'};
$model = $db->{'dat'}{'model'};
$makemodel = $db->{'dat'}{'makemodel'};
if (($make) && ($model)) {
$makemodel = "$make $model";
}
}
return ($rawqueue, $newfoomaticdata, $makemodel,
($config->{'spooler'} eq "cups" ? $beh : ()));
}
#fix to work on Ubuntu, where cupd runs not as root, but as cupsys user
#like system ("chown cupsys $ppdfile"), but
#changeowner function changes owner only if user exists on system
sub changeowner {
my ($username, $file) = @_;
my ($uid,$gid) = (-1, -1);
my $l;
$l = getpwnam($username); $uid = $l if defined($l);
$l = getgrnam($username); $gid = $l if defined($l);
chown $uid, $gid, $file;
}
sub writeppdfile {
my ($config, $ppdfile, $rawqueue, $newfoomaticdata) = @_;
# Save old $ppdfile, if any
system("cp -f \'$ppdfile\' \'$ppdfile.old\'")
if (-f $ppdfile);
if ($rawqueue) {
# Raw queue with $postpipe, use a "PPD" only containing the
# $postpipe (LPRng, LPD, and no spooler only)
if (((defined $db->{'dat'}{'postpipe'} && $db->{'dat'}{'postpipe'} ne "") &&
(($config->{'spooler'} eq 'lprng') ||
($config->{'spooler'} eq 'lpd'))) ||
($config->{'spooler'} eq 'direct')) {
open PPDFILE, "> $ppdfile" or die "Cannot write \'$ppdfile\'!\n";
print PPDFILE "*PPD-Adobe: \"4.3\"\n*%\n";
print PPDFILE "*% This is a raw (driverless/unfiltered) " .
"queue, this PPD file only carries\n" .
"*% the postpipe.\n*%\n";
close PPDFILE;
$db->ppdsetdefaults($ppdfile);
chmod 0644, $ppdfile;
#fix to work on Ubuntu, where cupd runs not as root, but as cupsys user
#system ("chown cupsys $ppdfile");
#changeowner function changes owner only if user exists on system
changeowner("cupsys", $ppdfile);
} else {
if (-f $ppdfile) {
unlink "$ppdfile" or die "Cannot delete \'$ppdfile\'!\n";
}
}
} else {
if ($config->{'ppdfile'}) {
# Copy in the PPD file specified on the command line
if ($config->{'ppdfile'} !~ /\.gz$/i) {
# Uncompressed PPD file
system("cp -f \'$config->{'ppdfile'}\' \'$ppdfile\'") and
die "Cannot copy \'$config->{'ppdfile'}\' to \'$ppdfile\'!\n";
} else {
# Compressed PPD file
system("$sysdeps->{'gzip'} -dc " .
"\'$config->{'ppdfile'}\' > " .
"\'$ppdfile\'") and
die "Cannot copy \'$config->{'ppdfile'}\' to \'$ppdfile\'!\n";
}
# Set default option settings and $postpipe
$db->ppdsetdefaults($ppdfile);
} elsif ($newfoomaticdata) {
# Generate the PPD file from the Foomatic database
open PPDFILE, "> $ppdfile" or die "Cannot write \'$ppdfile\'!\n";
print PPDFILE $db->getppd($config->{'shortgui'});
close PPDFILE;
} else {
# Keep the previous PPD file, only set the options and the
# $postpipe
$db->ppdsetdefaults($ppdfile);
}
# Correct the permissions of the PPD file
chmod 0644, $ppdfile;
#fix to work on Ubuntu, where cupd runs not as root, but as cupsys user
#system ("chown cupsys $ppdfile");
#changeowner function changes owner only if user exists on system
changeowner("cupsys", $ppdfile);
}
}
### Queue manipulation functions for both LPD and LPRng
sub setup_lpd {
my ($config) = $_[0];
# Read the previous /etc/printcap
my $pcap = load_lpd_printcap();
my ($ppdfile, $entry, $reconf, $p);
for $p (@{$pcap}) {
if ($p->{'names'}[0] eq $config->{'queue'}) {
$entry = $p;
$reconf = 1;
print "Reconfigure of ", Dumper($p) if $debug;
last;
}
}
# PPD file name
$ppdfile = sprintf('%s/lpd/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'}) if !$ppdfile;
# Get the data from the former queue if we reconfigure or copy a queue
# do also some checking of the user-supplied parameters
my ($rawqueue, $newfoomaticdata, $makemodel) =
getoldqueuedata($config, $reconf);
# Set the printer queue name line in /etc/printcap
if (!$reconf) {
if (!$rawqueue) {
$entry->{'names'}[0] = $config->{'queue'};
$entry->{'names'}[1] = $config->{'desc'};
$entry->{'names'}[2] = "$makemodel";
$entry->{'names'}[3] = $config->{'loc'};
} else {
$entry->{'names'}[0] = $config->{'queue'};
$entry->{'names'}[1] = $config->{'desc'};
$entry->{'names'}[2] = "Raw queue";
$entry->{'names'}[3] = $config->{'loc'};
}
} else {
if (!$rawqueue) {
$entry->{'names'}[2] = "$makemodel";
} else {
if (($entry->{'names'}[2] eq "Raw queue") ||
($config->{'driver'} eq "raw")) {
$rawqueue = 1;
$entry->{'names'}[2] = "Raw queue";
}
}
if (defined($config->{'desc'})) {
$entry->{'names'}[1] = $config->{'desc'};
}
if (defined($config->{'loc'})) {
$entry->{'names'}[3] = $config->{'loc'};
}
}
# These lines are always in /etc/printcap
$entry->{'str'}{'sd'} = sprintf('%s/%s',
$sysdeps->{'lpd-dir'},
$config->{'queue'});
$entry->{'str'}{'lf'} = $sysdeps->{'lpd-log'};
$entry->{'num'}{'mx'} = '0';
$entry->{'bool'}{'sh'} = 1;
# Lines depending on the printer/spooler
if (!$rawqueue) {
if ($config->{'spooler'} eq "lpd") {
$entry->{'str'}{'ppdfile'} = $ppdfile; # For the GPR printing GUI
delete $entry->{'str'}{'ppd'};
$entry->{'str'}{'if'} = $sysdeps->{'foomatic-rip'};
$entry->{'str'}{'af'} = $ppdfile;
delete $entry->{'bool'}{'force_localhost'};
delete $entry->{'str'}{'filter_options'};
} elsif ($config->{'spooler'} eq "lprng") {
$entry->{'str'}{'ppd'} = $ppdfile; # for LPRng PPD support
$entry->{'str'}{'if'} = $sysdeps->{'foomatic-rip'};
$entry->{'bool'}{'force_localhost'} = 1;
delete $entry->{'str'}{'ppdfile'};
delete $entry->{'str'}{'af'};
delete $entry->{'str'}{'filter_options'};
} else {
die "The spooler $config->{'spooler'} is not supported " .
"by this function!\n";
}
} else {
delete $entry->{'str'}{'if'};
delete $entry->{'str'}{'af'};
delete $entry->{'str'}{'filter_options'};
delete $entry->{'str'}{'ppd'};
if ($config->{'spooler'} eq "lpd") {
delete $entry->{'bool'}{'force_localhost'};
} elsif ($config->{'spooler'} eq "lprng") {
$entry->{'bool'}{'force_localhost'} = 1;
} else {
die "The spooler $config->{'spooler'} is not supported " .
"by this function!\n";
}
}
# If printing job has to be passed through a special program, put the
# command line into $postpipe (for example for Socket, Samba, ...)
my $postpipe = "";
if ((!$reconf) or ($config->{'connect'})) {
# Set up connection type
# Remove "rm" and "rp" tags to avoid problems when overwriting a
# raw queue
delete $entry->{'str'}{'rm'};
delete $entry->{'str'}{'rp'};
# All URIs ("-c" option) have the same syntax as URIs in CUPS ("-v"
# option of "lpadmin").
my $file;
if ($config->{'connect'} =~ m!^(file|usb|parallel|serial):(.*)!) {
# Local printer or printing to a file
$file = $2;
if ($config->{'connect'} =~ m!^usb://!) {
# Queue with printer-bound USB URI transferred from CUPS,
# as LPD/LPRng does not support these URIs, translate it
# back to a standard USB device URI
$file = cups_usb_printer_uri_to_device_uri($file);
}
if (! -e $file) {
warn "The device or file $file doesn't exist? " .
"Working anyway.\n";
}
if (($file =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($file =~ m!^/dev/ptal-printd/(.+)$!) ||
($file =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate URI for ptal-printd to postpipe using the
# "ptal-connect" command
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$postpipe = "$sysdeps->{'ptal-connect'} $devname -print";
$entry->{'str'}{'lp'} = "/dev/null";
} else {
$entry->{'str'}{'lp'} = $file;
}
} elsif ($config->{'connect'} =~ m!^ptal://?([^/].*)$!) {
# HPOJ MLC protocol
my $devname = $1;
$postpipe = "$sysdeps->{'ptal-connect'} $devname -print";
$entry->{'str'}{'lp'} = "/dev/null";
} elsif ($config->{'connect'} =~ m!^mtink:/(.+)$!) {
# Printing through "mtinkd"
$entry->{'str'}{'lp'} = "$sysdeps->{'mtink-pipes'}/$1";
} elsif ($config->{'connect'} =~ m!^lpd://([^/]+)/([^/]+)$!) {
# Remote LPD
my $remhost = $1;
my $remqueue = $2;
if (($rawqueue) && ($config->{'spooler'} eq "lpd")) {
$entry->{'str'}{'rm'} = $remhost;
$entry->{'str'}{'rp'} = $remqueue;
delete $entry->{'str'}{'lp'};
} elsif( ($config->{'spooler'} eq "lprng")) {
delete $entry->{'str'}{'rm'};
delete $entry->{'str'}{'rp'};
$entry->{'str'}{'lp'} = "$remqueue\@$remhost";
} else {
# classic LPD does not support sending jobs to a server with the
# "rm" and "rp" tags in /etc/printcap and filtering it
# before ("if" tag). So when we do not set up a raw queue,
# we do not
#
# $entry->{'str'}{'rm'} = $remhost;
# $entry->{'str'}{'rp'} = $remqueue;
#
# but use "rlpr" in a $postpipe. Note that "rlpr" prints a
# banner page by default, "-h" suppresses it. "rlpr" must
# be SUID "root".
$postpipe = "$sysdeps->{'rlpr'} -q -h -P " .
"$remqueue\@$remhost";
$entry->{'str'}{'lp'} = "/dev/null";
}
} elsif ($config->{'connect'} =~
m!^socket://([^/:]+):([0-9]+)/?$!) {
# Socket (AppSocket/HP JetDirect)
my $remhost = $1;
my $remport = $2;
if( ($config->{'spooler'} eq "lprng")) {
$entry->{'str'}{'lp'} = "$remhost\%$remport";
} else {
$postpipe = "$sysdeps->{'nc'} -w 1 $remhost $remport";
$entry->{'str'}{'lp'} = "/dev/null";
}
} elsif ($config->{'connect'} =~ m!^smb://(.*)$!) {
# SMB (Printer on Windows server)
my $parameters = $1;
# Get the user's login and password from the URI
my $smbuser = "";
my $smbpassword = "";
if ($parameters =~ m!([^@]*)@([^@]+)!) {
my $login = $1;
$parameters = $2;
if ($login =~ m!([^:]*):([^:]*)!) {
$smbuser = $1;
$smbpassword = $2;
} else {
$smbuser = $login;
$smbpassword = "";
}
} else {
$smbuser = "GUEST";
$smbpassword = "";
}
# Get the workgroup, server, and share name
my $workgroup = "";
my $smbserver = "";
my $smbshare = "";
if ($parameters =~ m!([^/]*)/([^/]+)/([^/]+)$!) {
$workgroup = $1;
$smbserver = $2;
$smbshare = $3;
} elsif ($parameters =~ m!([^/]+)/([^/]+)$!) {
$workgroup = "";
$smbserver = $1;
$smbshare = $2;
} else {
die "The \"smb://\" URI must at least contain the " .
"server name and the share name!\n";
}
# Set up the command line for printing on the SMB server
$postpipe = "$sysdeps->{'smbclient'} '//$smbserver/$smbshare'";
if ($smbpassword ne "") {
warn("WARNING: smbclient password is visible in PPD file\n");
$postpipe .= " '$smbpassword'";
}
if ($smbuser ne "") {$postpipe .= " -U '$smbuser'";}
if ($workgroup ne "") {$postpipe .= " -W '$workgroup'";}
$postpipe .= " -N -P -c 'print -' ";
$entry->{'str'}{'lp'} = "/dev/null";
} elsif ($config->{'connect'} =~ m!^ncp://(.*)$!) {
my $parameters = $1;
# Get the user's login and password from the URI
my $ncpuser = "";
my $ncppassword = "";
if ($parameters =~ m!([^@]*)@([^@]+)!) {
my $login = $1;
$parameters = $2;
if ($login =~ m!([^:]*):([^:]*)!) {
$ncpuser = $1;
$ncppassword = $2;
} else {
$ncpuser = $login;
$ncppassword = "";
}
} else {
$ncpuser = "";
$ncppassword = "";
}
# Get the server and share name
my $ncpserver = "";
my $ncpqueue = "";
if ($parameters =~ m!([^/]+)/([^/]+)$!) {
$ncpserver = $1;
$ncpqueue = $2;
} else {
die "The \"ncp://\" URI must at least contain the " .
"server name and the queue name!\n";
}
# Set up the command line for printing on the Netware server
$postpipe = "$sysdeps->{'nprint'} -S $ncpserver";
if ($ncpuser ne "") {
$postpipe .= " -U $ncpuser";
if ($ncppassword ne "") {
warn("WARNING: ncp password is visible in PPD file\n");
$postpipe .= " -P $ncppassword";
} else {
$postpipe .= " -n";
}
}
$postpipe .= " -q $ncpqueue -N - 2>/dev/null";
$entry->{'str'}{'lp'} = "/dev/null";
} elsif ($config->{'connect'} =~ m!^postpipe:(.*)$!) {
# Pipe output into a command
$postpipe = $1;
$entry->{'str'}{'lp'} = "/dev/null";
} elsif ($config->{'connect'}) {
$entry->{'str'}{'lp'} = '/dev/null';
die ("The URI \"$config->{'connect'}\" is not supported " .
"for LPD/LPRng or you have\nmistyped.\n");
} else {
print STDERR "You must specify a connection with -c.\n";
help();
exit(1);
}
# Put $postpipe into the data structure, so that it will be
# inserted into the PPD file
if ($postpipe ne "") {
$postpipe = "| $postpipe";
$db->{'dat'}{'postpipe'} = $postpipe;
} else {
undef $db->{'dat'}{'postpipe'};
}
} else {
# Keep previous connection type
# Use previous $postpipe
if (defined($db->{'dat'}{'postpipe'})) {
$postpipe = $db->{'dat'}{'postpipe'};
}
}
# When we have a $postpipe we never write to a device
if ($postpipe ne "") {
$entry->{'str'}{'lp'} = '/dev/null';
if ($config->{'spooler'} eq "lpd") {
$entry->{'str'}{'if'} = $sysdeps->{'foomatic-rip'};
$entry->{'str'}{'af'} = $ppdfile;
} elsif ($config->{'spooler'} eq "lprng") {
$entry->{'str'}{'if'} = $sysdeps->{'foomatic-rip'};
$entry->{'str'}{'ppd'} = $ppdfile;
$entry->{'bool'}{'force_localhost'} = 1;
} else {
die "The spooler $config->{'spooler'} is not supported " .
"by this function!\n";
}
}
# Various file setup
mkdir $sysdeps->{'foo-etc'}, 0755;
mkdir "$sysdeps->{'foo-etc'}/lpd", 0755;
mkdir $entry->{'str'}{'sd'}, 0755;
# Lead with a blank line for new entries
push (@{$entry->{'comments'}}, "\n")
if (!$reconf);
# Put in a useful comment for both new and old entries
push (@{$entry->{'comments'}},
sprintf ("\# Entry edited %s by $progname.",
scalar(localtime(time))),
"\# Additional configuration atop $ppdfile");
# Add to the printcap if a new entry
if (!$reconf) {
push(@{$pcap}, $entry);
}
# Generate/write te PPD file
writeppdfile($config, $ppdfile, $rawqueue, $newfoomaticdata);
# Make sure that /var/spool/lp-errs exists
system "touch $sysdeps->{'lpd-log'}";
chmod 0600, $sysdeps->{'lpd-log'};
my ($lpuid, $lpgid) = (-1, -1);
my $l;
$l = getpwnam("lp"); $lpuid = $l if defined($l);
$l = getgrnam("lp"); $lpgid = $l if defined($l);
chown $lpuid, $lpgid, $sysdeps->{'lpd-log'};
# Write back /etc/printcap
my $printcap = $sysdeps->{'lpd-pcap'};
rename $printcap, "$printcap.old" or die "Cannot backup $printcap!\n";
open PRINTCAP, "> $printcap" or die "Cannot write $printcap!\n";
print PRINTCAP dump_lpd_printcap($config, $pcap);
close PRINTCAP;
chmod 0644, $printcap;
# In case of LPRng, give SIGHUP to the daemon, LPRng needs this to
# recognize a new queue
if ($config->{'spooler'} eq "lprng") {
# first check configuration
system("$sysdeps->{'lprng-checkpc'} -f > /dev/null 2>&1");
# now signal to use it
system("$sysdeps->{'lpd-lpc'} reread > /dev/null 2>&1");
}
return 1;
}
sub default_lpd {
my ($config) = $_[0];
my $name = $config->{'queue'};
my $pcap = load_lpd_printcap();
# Add the alias "lp" to the /etc/printcap entry to make LPD considering
# the chosen printer as default printer
# Some stuff for renaming a queue named "lp"
my $nppdfile = undef;
my $newname = undef;
my $rawqueue = 0;
my @newcap;
for (@{$pcap}) {
my $p = $_;
if ($p->{'names'}[0] eq $name) {
$p->{'names'}[4] = 'lp';
} else {
# Rename a printer whose first name is 'lp'
if ($p->{'names'}[0] eq 'lp') {
# Do we have a raw queue?
if ((!defined($p->{'str'}{'if'})) ||
($p->{'str'}{'if'} ne $sysdeps->{'foomatic-rip'})) {
$rawqueue = 1;
}
# Search for a free name
my $i = 0;
my $namefound = 0;
while(!$namefound) {
my $pp;
my $nameinuse = 0;
for $pp (@{$pcap}) {
if (defined($pp->{'names'})) {
my $n;
for $n (@{$pp->{'names'}}) {
if ($n eq "lp$i") {
$nameinuse = 1;
last;
}
}
if ($nameinuse) {
$i++;
last;
}
}
}
$namefound = 1 - $nameinuse;
}
$newname = "lp$i";
# Old PPD file name
my $ppdfile = sprintf('%s/lpd/lp.ppd',
$sysdeps->{'foo-etc'});
# New PPD file name
my $nppdfile = sprintf('%s/lpd/%s.ppd',
$sysdeps->{'foo-etc'},
$newname);
# Rename the printer
$p->{'names'}[0] = $newname;
my $oldspooldir = $p->{'str'}{'sd'};
$p->{'str'}{'sd'} = sprintf('%s/%s',
$sysdeps->{'lpd-dir'},
$newname);
if ($p->{'str'}{'af'} =~ /\.ppd$/) {
$p->{'str'}{'af'} = $nppdfile;
}
# Rename old $ppdfile, if any
rename $ppdfile, $nppdfile
if (-f $ppdfile);
# Rename the spool directory
rename $oldspooldir, $p->{'str'}{'sd'}
if (-d $oldspooldir);
# Put out warning
warn("WARNING: Printer \"lp\" renamed to \"$newname\".\n");
}
# Remove 'lp' as alias name
my $n;
for $n (@{$p->{'names'}}) {
if ($n eq 'lp') {
$n = '';
}
}
}
push (@newcap, $p);
}
my @newprintcap = dump_lpd_printcap($config, \@newcap);
my $printcap = $sysdeps->{'lpd-pcap'};
rename $printcap, "$printcap.old" or die "Cannot backup $printcap!\n";
open PRINTCAP, "> $printcap" or die "Cannot write $printcap!\n";
print PRINTCAP @newprintcap;
close PRINTCAP;
chmod 0644, $printcap;
return 1;
}
sub default_lprng {
my ($config) = $_[0];
my $name = $config->{'queue'};
my $pcap = load_lpd_printcap();
# Move the /etc/printcap entry for the chosen printer to the first place
# so that LPRng considers it as the default printer
my @newcap;
for (@{$pcap}) {
push (@newcap, $_)
if ($_->{'names'}[0] eq $name);
}
for (@{$pcap}) {
push (@newcap, $_)
unless ($_->{'names'}[0] eq $name);
}
my @newprintcap = dump_lpd_printcap($config, \@newcap);
my $printcap = $sysdeps->{'lpd-pcap'};
rename $printcap, "$printcap.old" or die "Cannot backup $printcap!\n";
open PRINTCAP, "> $printcap" or die "Cannot write $printcap!\n";
print PRINTCAP @newprintcap;
close PRINTCAP;
chmod 0644, $printcap;
# In case of LPRng, give SIGHUP to the daemon, LPRng needs this to
# recognize the changes
if ($config->{'spooler'} eq "lprng") {
system("$sysdeps->{'lpd-lpc'} reread > /dev/null 2>&1");
system("$sysdeps->{'lprng-checkpc'} -f > /dev/null 2>&1");
}
return 1;
}
sub delete_lpd {
my ($config) = $_[0];
my $name = $config->{'queue'};
my $pcap = load_lpd_printcap();
my @newcap;
for (@{$pcap}) {
push (@newcap, $_)
unless ($_->{'names'}[0] eq $name);
}
my @newprintcap = dump_lpd_printcap($config, \@newcap);
my $printcap = $sysdeps->{'lpd-pcap'};
rename $printcap, "$printcap.old" or die "Cannot backup $printcap!\n";
open PRINTCAP, "> $printcap" or die "Cannot write $printcap!\n";
print PRINTCAP @newprintcap;
close PRINTCAP;
chmod 0644, $printcap;
# PPD file name
my $ppdfile = sprintf('%s/lpd/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Rename old $ppdfile, if any
rename $ppdfile, "$ppdfile.old"
if (-f $ppdfile);
# In case of LPRng, give SIGHUP to the daemon, LPRng needs this to
# recognize the changes
if ($config->{'spooler'} eq "lprng") {
system("$sysdeps->{'lpd-lpc'} reread > /dev/null 2>&1");
system("$sysdeps->{'lprng-checkpc'} -f > /dev/null 2>&1");
}
return 1;
}
sub query_lpd {
my ($config) = @_;
# User requests data of a printer/driver combo to see the options before
# installing a queue
if (($opt_P) && ((($config->{'driver'}) && ($config->{'printer'}) &&
($config->{'driver'} ne "raw")) || ($config->{'ppdfile'}))) {
if ($opt_n) {
my $olddatablob = load_lpd_datablob($opt_n);
print_perl_combo_data($config, $olddatablob);
} else {
print_perl_combo_data($config);
}
return;
}
my $i = $ARGV[0];
if (!defined($i)) {$i = 0;}
my $pcap = load_lpd_printcap();
my $p;
if (!$opt_P) {
print "<queues>\n";
}
# Query the default printer
my $default;
if (!defined($config->{'queue'})) {
if ($config->{'spooler'} eq "lpd") {
# Under LPD the default printer is the printer which has
# "lp" as its name or as an alias name
my $def_firstname = undef;
for $p (@{$pcap}) {
if (defined($p->{'names'})) {
my $n;
for $n (@{$p->{'names'}}) {
if ($n eq 'lp') {
$def_firstname = $p->{'names'}[0];
last;
}
}
if (defined($def_firstname)) {
last;
}
}
}
if (defined($def_firstname)) {
$default = $def_firstname;
if (!$opt_P) {
print "<defaultqueue>$def_firstname</defaultqueue>\n";
}
}
} else {
# Under LPRng the default printer is the first entry in
# /etc/printcap
for $p (@{$pcap}) {
if (defined($p->{'names'})) {
$default = $p->{'names'}[0];
if (!$opt_P) {
print "<defaultqueue>$p->{'names'}[0]" .
"</defaultqueue>\n";
}
last;
}
}
}
}
for $p (@{$pcap}) {
# enpty end entry for trailing comments
next if !defined($p->{'names'});
# were we invoked for only one queue?
next if (defined($config->{'queue'})
and $config->{'queue'} ne $p->{'names'}[0]);
# load the queue data
$db->{'dat'} = load_lpd_datablob($p->{'names'}[0]);
# extract the queue data block
my $c = $db->{'dat'}{'queuedata'};
if ($opt_P) {
if ($p->{'names'}[0] eq $default) {
$db->{'dat'}{'queuedata'}{'default'} = 1;
} else {
$db->{'dat'}{'queuedata'}{'default'} = 0;
}
$db->{'dat'}{'queuedata'}{'remote'} = 0;
my $asciidata = $db->getascii();
$asciidata =~ s/\$VAR1/\$QUEUES[$i]/g;
print $asciidata;
$i ++;
} else {
# and get it to standard output
dump_config($c);
}
}
if (!$opt_P) {
print "</queues>\n";
}
return;
}
### Queue manipulation functions for CUPS
sub setup_cups {
my ($config) = $_[0];
# PPD file name
# (/etc/foomatic/cups/ will be a link to /etc/cups/ppd/)
my $ppdfile = sprintf('%s/ppd/%s.ppd',
$sysdeps->{'cups-etc'},
$config->{'queue'});
# Get the data from the former queue if we reconfigure or copy a queue
# do also some checking of the user-supplied parameters
my ($rawqueue, $newfoomaticdata, $makemodel, $beh) =
getoldqueuedata($config, 1);
# Here we set up the command line for the "lpadmin" command
my $lpadminline =
"$sysdeps->{'cups-admin'} -p \"$config->{'queue'}\" -E";
# Use manufacturer and model as description when no description is
# provided
if (defined($config->{'desc'})) {
$lpadminline .= " -D \"$config->{'desc'}\"";
} else {
# Before we overwrite the description field with manufacturer
# and model, check if there is some old contents
my $pconf = load_cups_printersconf();
my $p;
my $olddesc;
for $p (@{$pconf}) {
next if (defined($config->{'queue'})
and $config->{'queue'} ne $p->{'name'});
$olddesc = $p->{'Info'};
}
if (!$olddesc) {
if (!$rawqueue) {
$lpadminline .= " -D \"$makemodel\"";
} else {
$lpadminline .= " -D \"Raw queue\"";
}
}
}
# Fill in the "location" field if something for it is provided.
if (defined($config->{'loc'})) {
$lpadminline .= " -L \"$config->{'loc'}\"";
}
# PPD file argument for the printer
if (!$rawqueue) {
$lpadminline .= " -P \'$ppdfile\'";
}
# All URIs ("-c" option) have the same syntax as URIs in CUPS
# ("-v" option of "lpadmin"). Here the old "file:/" URIs are
# translated to the form which CUPS needs. All other URIs are
# simply passed to lpadmin.
my $cupsuri = "";
if (defined($config->{'connect'})) {
if ($config->{'connect'} =~ m!^(file|usb|parallel|serial):(.*)$!) {
# Translate "file:/" into the prefix needed by CUPS, if
# necessary
$cupsuri = $2;
if ((($cupsuri =~ m!$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($cupsuri =~ m!/dev/ptal-printd/(.+)$!) ||
($cupsuri =~ m!/var/run/ptal-printd/(.+)$!)) &&
(-x "$sysdeps->{'cups-backends'}/ptal")) {
# Translate URI for ptal-printd (does not work with CUPS
# 1.1.12 and newer) to URI for the "ptal" CUPS backend
# script (if the script is there)
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$cupsuri = "ptal:/$devname";
} elsif ((($cupsuri =~ m!^$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($cupsuri =~ m!^/var/mtink/(.+)$!)) &&
(-x "$sysdeps->{'cups-backends'}/mtink")) {
# Translate URI for mtinkd (does not work with CUPS
# 1.1.12 and newer) to URI for the "mtink" CUPS backend
# script (if the script is there)
$cupsuri = "mtink:/$1";
} elsif ($config->{'connect'} =~ m!usb!i) {
$cupsuri = cups_usb_device_uri_to_printer_uri($cupsuri);
$cupsuri = "usb:$cupsuri";
} elsif (($cupsuri =~ m!lp[0-9]!) || ($cupsuri =~ m!LP[0-9]!)||
($cupsuri =~ m!parallel!)) {
$cupsuri = "parallel:$cupsuri";
} elsif (($cupsuri =~ m!tty!) || ($cupsuri =~ m!TTY!) ||
($cupsuri =~ m!serial!)) {
$cupsuri = "serial:$cupsuri";
} else {
$cupsuri = "file:$cupsuri";
}
} elsif (($config->{'connect'} =~ m!^ptal://?([^/].*)$!) &&
(!-x "$sysdeps->{'cups-backends'}/ptal")) {
# If there is no "ptal" backend script for CUPS, use an URI
# pointing to the pipe set up by ptal-printd.
my $devname = $1;
$devname =~ tr/:/_/;
$cupsuri = "file:$sysdeps->{'ptal-pipes'}/$devname";
} elsif (($config->{'connect'} =~ m!^mtink:/(.*)$!) &&
(!-x "$sysdeps->{'cups-backends'}/mtink")) {
# If there is no "mtink" backend script for CUPS, use an URI
# pointing to the pipe set up by mtinkd.
$cupsuri = "file:$sysdeps->{'mtink-pipes'}/$1";
} else {
$cupsuri=$config->{'connect'};
}
# Correct PTAL URIs: "ptal:/..." for HPOJ 0.9, "ptal://..." for newer
# HPOJ
if ($cupsuri =~ m!^ptal:/!) {
$cupsuri = cups_correct_ptal_uri($cupsuri);
}
}
# Are there changes in the error handling of the backend?
if (((defined($config->{'dd'})) &&
(((defined($beh->{'dd'})) &&
($config->{'dd'} ne $beh->{'dd'})) ||
($config->{'dd'} != 0))) ||
((defined($config->{'att'})) &&
(((defined($beh->{'att'})) &&
($config->{'att'} ne $beh->{'att'})) ||
($config->{'att'} != 1))) ||
((defined($config->{'delay'})) &&
(((defined($beh->{'delay'})) &&
($config->{'delay'} ne $beh->{'delay'})) ||
($config->{'delay'} != 30)))) {
if (!defined($config->{'dd'})) {
$config->{'dd'} = (defined($beh->{'dd'}) ? $beh->{'dd'} : 0);
}
if (!defined($config->{'att'})) {
$config->{'att'} = (defined($beh->{'att'}) ? $beh->{'att'} : 1);
}
if (!defined($config->{'delay'})) {
$config->{'delay'} = (defined($beh->{'delay'}) ?
$beh->{'delay'} : 30);
}
$cupsuri = $beh->{'uri'} if !$cupsuri;
# Do only add the "beh" wrapper backend when it is really needed
# (More than one retry and/or no disabling) and if the queue is not
# using the HPLIP ("hp") backend, as otherwise the "hp-toolbox"
# will not list the printer any more. HPLIP does infinite retries
# in 30-sec intervals anyway.
if (($cupsuri) && ($cupsuri !~ m!^hp(fax|):/!) &&
(($config->{'dd'} != 0) || ($config->{'att'} != 1))) {
$cupsuri = sprintf("beh:/%d/%d/%d/%s",
$config->{'dd'}, $config->{'att'},
$config->{'delay'}, $cupsuri);
}
}
if ($cupsuri) {
$lpadminline .= " -v \"$cupsuri\"";
}
# Directory setup, let the Foomatic PPD directory for CUPS be the same
# as /etc/cups/ppd/ (where CUPS stores the PPDs of the installed queues)
mkdir $sysdeps->{'foo-etc'}, 0755;
symlink "$sysdeps->{'cups-etc'}/ppd/", "$sysdeps->{'foo-etc'}/cups";
# In CUPS we never have a $postpipe
# (when we get a $postpipe from a source PPD file from another
# spooler, we don't need to remove it really, because it will be
# ignored by foomatic-rip, uncomment this to remove it)
#$db->{'dat'}{'postpipe'} = "";
# Generate/write te PPD file
writeppdfile($config, $ppdfile, $rawqueue, $newfoomaticdata);
# Execute the lpadmin command to set up the new queue
if (system $lpadminline) {
# Remove the config files
unlink "$ppdfile"
if (-f "$ppdfile");
# Revert changed config files
rename "$ppdfile.old", "$ppdfile"
if (-f "$ppdfile.old");
die "Could not set up/change the queue \"$config->{'queue'}\"!\n";
}
return 1;
}
sub default_cups {
my ($config) = $_[0];
if ($< == 0) {
# (/etc/cups/printers.conf can only be manipulated by root)
# This line sets the default printer in /etc/cups/printers.conf
my $command = "$sysdeps->{'cups-admin'} -d " .
"\"$config->{'queue'}\" > /dev/null";
# Do it! (Ignore errors silently)
system $command;
}
# This line sets the default printer in /etc/cups/lpoptions
# (required for setting a remote queue as default)
my $command = "$sysdeps->{'cups-lpoptions'} -d " .
"\"$config->{'queue'}\" > /dev/null";
# Do it!
system $command and
die "Unable to set queue \"$config->{'queue'}\" as default!\n";
}
sub delete_cups {
my ($config) = $_[0];
# This line deletes the old printer queue
my $queuedeleteline =
"$sysdeps->{'cups-admin'} -x \"$config->{'queue'}\"";
# Do it!
system $queuedeleteline and
die "Unable to delete queue \"$config->{'queue'}\"!\n";
return 1;
}
sub query_cups {
my ($config) = @_;
# User requests data of a printer/driver combo to see the options before
# installing a queue
if (($opt_P) && ((($config->{'driver'}) && ($config->{'printer'}) &&
($config->{'driver'} ne "raw")) || ($config->{'ppdfile'}))) {
if ($opt_n) {
my $olddatablob = load_cups_datablob($opt_n);
print_perl_combo_data($config, $olddatablob);
} else {
print_perl_combo_data($config);
}
return;
}
my $i = $ARGV[0];
if (!defined($i)) {$i = 0;}
my $pconf = load_cups_printersconf();
if (defined($opt_r)) {$opt_r = undef;}
my $p;
if (!$opt_P) {
print "<queues>\n";
}
# Query the default printer
my $default = '';
if (!defined($config->{'queue'})) {
open DEFAULT, "$sysdeps->{'cups-lpstat'} -d |" or
die "Could not run $sysdeps->{'cups-lpstat'}!\n";
my $defaultstr = <DEFAULT>;
close DEFAULT;
if ($defaultstr =~ m!\S+:\s+(\S+)$!) {
$default = $1;
if (!$opt_P) {
print "<defaultqueue>$default</defaultqueue>\n";
}
}
}
for $p (@{$pconf}) {
# were we invoked for only one queue?
next if (defined($config->{'queue'})
and $config->{'queue'} ne $p->{'name'});
# load the queue data
$db->{'dat'} = load_cups_datablob($p->{'name'});
# Enter info for remote queue
if ($p->{'remote'}) {
$db->{'dat'}{'queuedata'}{'foomatic'} = 0;
$db->{'dat'}{'queuedata'}{'spooler'} = 'cups';
$db->{'dat'}{'queuedata'}{'queue'} = $p->{'name'};
$db->{'dat'}{'queuedata'}{'connect'} = $p->{'DeviceURI'};
$db->{'dat'}{'queuedata'}{'description'} = $p->{'Info'};
$db->{'dat'}{'queuedata'}{'loc'} = $p->{'Location'};
$db->{'dat'}{'queuedata'}{'remote'} = 1;
} else {
$db->{'dat'}{'queuedata'}{'remote'} = 0;
}
# extract the queue data block
my $c = $db->{'dat'}{'queuedata'};
if ($opt_P) {
if ($p->{'name'} eq $default) {
$db->{'dat'}{'queuedata'}{'default'} = 1;
} else {
$db->{'dat'}{'queuedata'}{'default'} = 0;
}
my $asciidata = $db->getascii();
$asciidata =~ s/\$VAR1/\$QUEUES[$i]/g;
print $asciidata;
$i ++;
} else {
# and get it to standard output
dump_config($c);
}
}
if (!$opt_P) {
print "</queues>\n";
}
return;
}
### Queue manipulation functions for PDQ
sub setup_pdq {
my ($config) = $_[0];
# Read the previous /usr/lib/pdq/printrc
my $printrc = load_pdq_printrc();
my ($ppdfile, $driverfile, $entry, $reconf, $p);
$reconf = 0;
for $p (@{$printrc}) {
if ((defined($p->{'name'})) &&
($p->{'name'} eq $config->{'queue'})) {
$entry = $p;
$reconf = 1;
last;
use Data::Dumper;
print "Reconfigure of ", Dumper($p);
}
}
# Config file names
$ppdfile = sprintf('%s/pdq/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
$driverfile = sprintf('%s/pdq/driverdescr/%s.pdq',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Get the data from the former queue if we reconfigure or copy a queue
# do also some checking of the user-supplied parameters
my ($rawqueue, $newfoomaticdata, $makemodel) =
getoldqueuedata($config, $reconf);
# Set the initial line of the "printer" block in /usr/lib/pdq/printrc
$entry->{'name'} = $config->{'queue'};
# Location field
if ((defined($config->{'loc'})) || (!$reconf)) {
$entry->{'location'} = "\"$config->{'loc'}\"";
}
# Model/Description field
if (defined($config->{'desc'})) {
$entry->{'model'} = "\"$config->{'desc'}\"";
} elsif (!$entry->{'model'}) {
if (!$rawqueue) {
$entry->{'model'} = "\"$makemodel\"";
} else {
$entry->{'model'} = "\"Raw printer\"";
}
}
# Create directories
mkdir $sysdeps->{'foo-etc'}, 0755;
mkdir $sysdeps->{'foo-etc'} . '/pdq', 0755;
mkdir $sysdeps->{'foo-etc'} . '/pdq/driverdescr', 0755;
# Make the printer driver descriptions in /etc/foomatic/pdq visible
# for PDQ
# symlink $sysdeps->{'foo-etc'} . '/pdq', $sysdeps->{'pdq-foomatic'};
# Save old driver file, use the "~" to make it appear an editor
# backup so that PDQ does not parse it.
# Save old $driverfile, if any
rename $driverfile, "$driverfile.old~"
if (-f $driverfile);
# Generate/write the PPD file
writeppdfile($config, $ppdfile, $rawqueue, $newfoomaticdata);
# Create driver description file
if ($rawqueue) {
system("$sysdeps->{'foomatic-rip'} --genrawpdq $driverfile") and
die "Cannot create $driverfile!\n";
} else {
system("$sysdeps->{'foomatic-rip'} --ppd \'$ppdfile\' --genpdq " .
"$driverfile") and
die "Cannot create $driverfile!\n";
}
# PDQ configuration file
# Driver fields
# Extract driver name
my $driverdesc = `cat $driverfile`;
$driverdesc =~ m!^\s*driver\s*(\"\S*\-\d+\")!m;
# Driver-specific entries
$entry->{'driver'} = $1;
$entry->{'driver_opts'} = "\{ \}";
$entry->{'driver_args'} = "\{ \}";
# Interface fields
# All URIs ("-c" option) have the same syntax as URIs in CUPS ("-v"
# option of "lpadmin").
if ($config->{'connect'} =~ m!^(file|usb|parallel|serial):(.*)!) {
# Local printer or printing to a file
my $file = $2;
if ($config->{'connect'} =~ m!^usb://!) {
# Queue with printer-bound USB URI transferred from CUPS,
# as PDQ does not support these URIs, translate it
# back to a standard USB device URI
$file = cups_usb_printer_uri_to_device_uri($file);
}
if (! -e $file) {
warn "The device or file $file doesn't exist? " .
"Working anyway.\n";
}
$entry->{'interface'} = "\"local-port\"";
$entry->{'interface_opts'} = "\{ \}";
$entry->{'interface_args'} = "\{ \"PORT\" = \"$file\" \}";
} elsif ($config->{'connect'} =~ m!^ptal://?([^/].*)$!) {
# HPOJ MLC protocol
my $devname = $1;
$devname =~ tr/:/_/;
$entry->{'interface'} = "\"local-port\"";
$entry->{'interface_opts'} = "\{ \}";
$entry->{'interface_args'} = "\{ \"PORT\" = " .
"\"$sysdeps->{'ptal-pipes'}/$devname\" \}";
} elsif ($config->{'connect'} =~ m!^mtink:/(.+)$!) {
# Printing through "mtinkd"
$entry->{'interface'} = "\"local-port\"";
$entry->{'interface_opts'} = "\{ \}";
$entry->{'interface_args'} = "\{ \"PORT\" = " .
"\"$sysdeps->{'mtink-pipes'}/$1\" \}";
} elsif ($config->{'connect'} =~ m!^lpd://([^/]+)/([^/]+)$!) {
# Remote LPD
my $remhost = $1;
my $remqueue = $2;
$entry->{'interface'} = "\"bsd-lpd\"";
$entry->{'interface_opts'} = "\{ \}";
$entry->{'interface_args'} =
"\{ \"QUEUE\" = \"$remqueue\", \"REMOTE_HOST\" = " .
"\"$remhost\" \}";
} elsif ($config->{'connect'} =~ m!^socket://([^/:]+):([0-9]+)/?$!) {
# Socket (AppSocket/HP JetDirect)
my $remhost = $1;
my $remport = $2;
$entry->{'interface'} = "\"tcp-port\"";
$entry->{'interface_opts'} = "\{ \}";
$entry->{'interface_args'} =
"\{ \"REMOTE_PORT\" = \"$remport\", \"REMOTE_HOST\" = " .
"\"$remhost\" \}";
} elsif ($config->{'connect'}) {
die ("The URI \"$config->{'connect'}\" is not supported " .
"for PDQ or you have\nmistyped.\n");
} elsif (!$reconf) {
die "You must specify a connection with -c.\n";
}
# Add to the printrc if it is a new entry
if (!$reconf) {
push(@{$printrc}, $entry);
}
# Write back the modified printrc file
my $printrcname = $sysdeps->{'pdq-printrc'};
rename $printrcname, "$printrcname.old" or
die "Cannot backup $printrcname!\n";
open PRINTRC, "> $printrcname" or die "Cannot write $printrcname!\n";
print PRINTRC dump_pdq_printrc($printrc);
close PRINTRC;
chmod 0644, $printrcname;
return 1;
}
sub default_pdq {
my ($config) = $_[0];
# Determine the name of the config file to modify
my $printrcname = "";
if ($< == 0) {
$printrcname = "$sysdeps->{'pdq-printrc'}";
if (!(-f $printrcname)) {die "No file $printrcname!"};
} else {
$printrcname = "$ENV{HOME}/.printrc";
if (!(-f $printrcname)) {system "touch $printrcname"};
}
# Read the config file
open PRINTRC, "$printrcname" or die "Cannot open $printrcname!";
my @printrc = <PRINTRC>;
close PRINTRC;
# Remove all valid "default_printer" lines
($_ =~ /^\s*default_printer/ and $_="") foreach @printrc;
# Insert the new "default_printer" line
push @printrc, "default_printer $config->{'queue'}\n";
# Write back the modified config file
open PRINTRC, "> $printrcname" or die "Cannot open $printrcname!";
print PRINTRC @printrc;
close PRINTRC;
}
sub delete_pdq {
my ($config) = $_[0];
my $name = $config->{'queue'};
my $printrc = load_pdq_printrc();
my @newrc;
for (@{$printrc}) {
push (@newrc, $_)
unless (defined($_->{'name'}) && ($_->{'name'} eq $name));
}
my @newprintrc = dump_pdq_printrc(\@newrc);
my $printrcname = $sysdeps->{'pdq-printrc'};
rename $printrcname, "$printrcname.old" or
die "Cannot backup $printrcname!\n";
open PRINTRC, "> $printrcname" or die "Cannot write $printrcname!\n";
print PRINTRC @newprintrc;
close PRINTRC;
chmod 0644, $printrcname;
# Config file names
my $ppdfile = sprintf('%s/pdq/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
my $driverfile = sprintf('%s/pdq/driverdescr/%s.pdq',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Rename old $ppdfile, if any
rename $ppdfile, "$ppdfile.old"
if (-f $ppdfile);
# Rename old driverfile, if any, use the "~" to make it appear an
# editor backup so that PDQ does not parse it.
# Rename old $driverfile, if any
rename $driverfile, "$driverfile.old~"
if (-f $driverfile);
return 1;
}
sub query_pdq {
my ($config) = @_;
# User requests data of a printer/driver combo to see the options before
# installing a queue
if (($opt_P) && ((($config->{'driver'}) && ($config->{'printer'}) &&
($config->{'driver'} ne "raw")) || ($config->{'ppdfile'}))) {
if ($opt_n) {
my $olddatablob = load_pdq_datablob($opt_n);
print_perl_combo_data($config, $olddatablob);
} else {
print_perl_combo_data($config);
}
return;
}
my $i = $ARGV[0];
if (!defined($i)) {$i = 0;}
my $printrc = load_pdq_printrc();
my $p;
if (!$opt_P) {
print "<queues>\n";
}
# Query the default printer
my $default;
if (!defined($config->{'queue'})) {
open DEFAULT, "$sysdeps->{'pdq-print'} -h 2>&1 |" or
die "Could not run $sysdeps->{'pdq-print'}!\n";
my $defaultstr = join('', <DEFAULT>);
close DEFAULT;
if ($defaultstr =~ m!The\s+default\s+printer\s+is\s+(\S+)$!m) {
$default = $1;
if (!$opt_P) {
print "<defaultqueue>$default</defaultqueue>\n";
}
}
}
for $p (@{$printrc}) {
# Omit non-printer-block items
next if (!(defined($p->{'name'})));
# were we invoked for only one queue?
next if (defined($config->{'queue'})
and $config->{'queue'} ne $p->{'name'});
# load the queue data
$db->{'dat'} = load_pdq_datablob($p->{'name'});
# extract the queue data block
my $c = $db->{'dat'}{'queuedata'};
if ($opt_P) {
if ($p->{'name'} eq $default) {
$db->{'dat'}{'queuedata'}{'default'} = 1;
} else {
$db->{'dat'}{'queuedata'}{'default'} = 0;
}
$db->{'dat'}{'queuedata'}{'remote'} = 0;
my $asciidata = $db->getascii();
$asciidata =~ s/\$VAR1/\$QUEUES[$i]/g;
print $asciidata;
$i ++;
} else {
# and get it to standard output
dump_config($c);
}
}
if (!$opt_P) {
print "</queues>\n";
}
return;
}
### Queue manipulation functions for PPR
sub setup_ppr {
my ($config) = $_[0];
# Read the previous configuration
my $printrc = load_ppr_printers_conf();
my ($ppdfile, $entry, $reconf, $p);
$reconf = 0;
for $p (@{$printrc}) {
if ((defined($p->{'name'})) &&
($p->{'name'} eq $config->{'queue'})) {
$entry = $p;
$reconf = 1;
last;
use Data::Dumper;
print "Reconfigure of ", Dumper($p);
}
}
# PPD file name
$ppdfile = sprintf('%s/ppr/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Determine the PPR version in use
my $pprversion;
if (open VER, "$sysdeps->{'ppr-pprd'} --version |") {
my $ver = <VER>;
close VER;
$ver =~ /^\D*(\d+)\.(\d+)(\.(\d+)|)((a|alpha|b|beta|r|rc)(\d+|)|)/;
$pprversion = (1e8 * $1 + 1e6 * $2 + 1e4 * $4 +
($5 ? 100 * (ord(uc($6)) - 64) + $7 : 9999)) / 1e8;
} else {
# Could not determine version, so we set it to 0 (oldest possible)
$pprversion = 0;
}
# Get the data from the former queue if we reconfigure or copy a queue
# do also some checking of the user-supplied parameters
my ($rawqueue, $newfoomaticdata, $makemodel) =
getoldqueuedata($config, $reconf);
# Read out previous interface settings
my $interface = "";
my $address = "";
my $options = "";
my $interface_options = "";
if ($reconf) {
$interface = $entry->{'Interface'};
$address = $entry->{'Address'};
$interface_options = $entry->{'Options'};
if (($interface eq "foomatic-rip") ||
($interface eq "ppromatic")) {
if ($interface_options =~ /backend=(\S+)/) {
$interface = $1;
$interface_options =~ s/backend=(\S+)//;
if ($interface_options =~ /^\s*$/) {
$interface_options = "";
}
} else {
$interface = "";
}
}
}
# All URIs ("-c" option) have the same syntax as URIs in CUPS ("-v"
# option of "lpadmin").
if (defined($config->{'connect'})) {
$interface_options =~ s/smbuser=(\S+)//;
$interface_options =~ s/smbpassword=(\S+)//;
if ($config->{'connect'} =~ m!^(file|usb|parallel|serial):(.*)!) {
# Local printer or printing to a file
$address = $2;
if ($config->{'connect'} =~ m!^usb://!) {
# Queue with printer-bound USB URI transferred from CUPS,
# as PPR does not support these URIs, translate it
# back to a standard USB device URI
$address = cups_usb_printer_uri_to_device_uri($address);
}
if (! -e $address) {
warn "The device or file $address doesn't exist? " .
"Working anyway.\n";
}
if (($address =~ m!usb!) || ($address =~ m!USB!) ||
($address =~ m!$sysdeps->{'ptal-pipes'}!) ||
($address =~ m!/dev/ptal-printd!) ||
($address =~ m!/var/run/ptal-printd!) ||
($address =~ m!$sysdeps->{'mtink-pipes'}!) ||
($address =~ m!/var/mtink!)) {
$interface = "simple";
} elsif (($address =~ m!lp[0-9]!) || ($address =~ m!LP[0-9]!) ||
($address =~ m!parallel!)) {
$interface = "parallel";
} elsif (($address =~ m!tty!) || ($address =~ m!TTY!) ||
($address =~ m!serial!)) {
$interface = "serial";
} else {
$interface = "dummy";
}
$options = "";
} elsif ($config->{'connect'} =~ m!^ptal://?([^/].*)$!) {
# HPOJ MLC protocol
my $devname = $1;
$devname =~ tr/:/_/;
$address = "$sysdeps->{'ptal-pipes'}/$devname";
$interface = "simple";
$options = "";
} elsif ($config->{'connect'} =~ m!^mtink:/(.+)$!) {
# Printing through "mtinkd"
$address = "$sysdeps->{'mtink-pipes'}/$1";
$interface = "simple";
$options = "";
} elsif ($config->{'connect'} =~ m!^lpd://([^/]+)/([^/]+)$!) {
# Remote LPD
my $remhost = $1;
my $remqueue = $2;
$address = "${remqueue}\@${remhost}";
$interface = "lpr";
$options = "";
} elsif ($config->{'connect'} =~
m!^socket://([^/:]+):([0-9]+)/?$!) {
# Socket (AppSocket/HP JetDirect)
my $remhost = $1;
my $remport = $2;
$address = "$remhost:$remport";
$interface = "tcpip";
$options = "";
} elsif ($config->{'connect'} =~ m!^smb://(.*)$!) {
# SMB (Printer on Windows server)
my $parameters = $1;
# Get the user's login and password from the URI
my $smbuser = "";
my $smbpassword = "";
if ($parameters =~ m!([^@]*)@([^@]+)!) {
my $login = $1;
$parameters = $2;
if ($login =~ m!([^:]*):([^:]*)!) {
$smbuser = $1;
$smbpassword = $2;
} else {
$smbuser = $login;
$smbpassword = "";
}
} else {
$smbuser = "GUEST";
$smbpassword = "";
}
# When a password is given, a user name should be given, too.
if (($smbpassword ne "") && ($smbuser eq "")) {
$smbuser = "GUEST";
}
# The "smb" interface of PPR uses "ppr" as the SMB user when no
# user name is given. Usually one does not have such a user name
# under Windows. So use "GUEST" if no user name is given.
if ($smbuser eq "") {
$smbuser = "GUEST";
}
# Set the options for PPR's "smb" interface
$options = "";
if ($smbuser ne "") {
$options = "smbuser=\"$smbuser\"";
if ($smbpassword ne "") {
$options .= " smbpassword=\"$smbpassword\"";
}
}
# Get the workgroup, server, and share name
my $workgroup = "";
my $smbserver = "";
my $smbshare = "";
if ($parameters =~ m!([^/]*)/([^/]+)/([^/]+)$!) {
$workgroup = $1;
$smbserver = $2;
$smbshare = $3;
} elsif ($parameters =~ m!([^/]+)/([^/]+)$!) {
$workgroup = "";
$smbserver = $1;
$smbshare = $2;
} else {
die "The \"smb://\" URI must at least contain the " .
"server name and the share name!\n";
}
$address = "//$smbserver/$smbshare";
$interface = "smb";
} else {
die ("The URI \"$config->{'connect'}\" is not supported for " .
"PPR or you have\nmistyped.\n");
}
} elsif (!$reconf) {
die "You must specify a connection with -c.\n";
}
# Here we set up the command line for the "ppad interface" and the
# "ppad options" commands
my $ppad_interface = "";
my $ppad_options = "";
my $ppad_rip = "";
if ($rawqueue) {
$ppad_interface = "$sysdeps->{'ppr-ppad'} interface " .
"\"$config->{'queue'}\" $interface \"$address\"";
$ppad_options = "$sysdeps->{'ppr-ppad'} options " .
"\"$config->{'queue'}\" $options $interface_options";
$ppad_rip = "$sysdeps->{'ppr-ppad'} " .
"rip \"$config->{'queue'}\"";
} else {
if ($pprversion >= 1.50000102 ) { #1.50a2
$ppad_interface = "$sysdeps->{'ppr-ppad'} interface " .
"\"$config->{'queue'}\" $interface \"$address\"";
$ppad_options = "$sysdeps->{'ppr-ppad'} options " .
"\"$config->{'queue'}\" $options $interface_options";
if ($db->{'dat'}{'id'}) {
$ppad_rip = "$sysdeps->{'ppr-ppad'} " .
"rip \"$config->{'queue'}\" foomatic-rip x" .
# PPR 1.50a2 has a bug and needs at least one option for
# the command line of the PPR RIP, therefore we add the
# "0" in this case. The number is very likely not the
# name of any boolean option, so it will be ignored by
# foomatic-rip
(($pprversion < 1.50000103 ) ? " 0" : "");
} else {
$ppad_rip = "$sysdeps->{'ppr-ppad'} " .
"rip \"$config->{'queue'}\"";
}
} else {
$ppad_interface = "$sysdeps->{'ppr-ppad'} interface " .
"\"$config->{'queue'}\" foomatic-rip \"$address\"";
$ppad_options = "$sysdeps->{'ppr-ppad'} options " .
"\"$config->{'queue'}\" backend=\"$interface\" " .
"$options $interface_options";
$ppad_rip = "$sysdeps->{'ppr-ppad'} " .
"rip \"$config->{'queue'}\"";
}
}
# Execute the ppad commands to set up the new queue
if ((system $ppad_interface) ||
(system $ppad_options) ||
(system $ppad_rip)) {
die "Could not set up/change the queue \"$config->{'queue'}\"!\n";
}
# Use manufacturer and model as description when no description is
# provided
my($comment, $olddesc);
if (defined($config->{'desc'})) {
$comment = $config->{'desc'};
} else {
# Before we overwrite the description field with manufacturer
# and model, check if there is some old contents
if (($reconf) && ($entry->{'Comment'})) {
$olddesc = $entry->{'Comment'};
}
if (!$olddesc) {
if (!$rawqueue) {
$comment = "$makemodel";
} else {
$comment = "Raw queue";
}
}
}
if ($comment) {
my $ppad_comment = "$sysdeps->{'ppr-ppad'} comment " .
"\"$config->{'queue'}\" \"$comment\"";
if (system $ppad_comment) {
warn "Could not set description for the queue " .
"\"$config->{'queue'}\"!\n";
}
}
# Fill in the "location" field if something for it is provided.
if (defined($config->{'loc'})) {
my $ppad_location = "$sysdeps->{'ppr-ppad'} location " .
"\"$config->{'queue'}\" \"$config->{'loc'}\"";
if (system $ppad_location) {
warn "Could not set location for the queue " .
"\"$config->{'queue'}\"!\n";
}
}
# Various file setup
mkdir $sysdeps->{'foo-etc'}, 0755;
mkdir $sysdeps->{'foo-etc'} . '/ppr', 0755;
# Generate/write the PPD file
writeppdfile($config, $ppdfile, $rawqueue, $newfoomaticdata);
if ($rawqueue) {
my $ppad_ppd = "$sysdeps->{'ppr-ppad'} ppd " .
"\"$config->{'queue'}\" \"\" 2> /dev/null";
if (!system $ppad_ppd) {
# Automatic input tray selection not activated by default,
# because the feature requires manual choice of the paper types
# in the trays and other spoolers than PPR do not have automatic
# paper tray selection. In addition "ppop media <queue>" is
# broken for printers with a high number of input trays in their
# PPD files.
#my $ppad_bins = "$sysdeps->{'ppr-ppad'} bins delete " .
#"\"$config->{'queue'}\" \"" .
#join ('" "', @{$entry->{'Bins'}}) . "\"";
#if (system $ppad_bins) {
#warn "Could not set paper input trays for the " .
#"queue \"$config->{'queue'}\"!\n";
#}
my $ppad_deffiltopts = "$sysdeps->{'ppr-ppad'} " .
"deffiltopts \"$config->{'queue'}\" 2> /dev/null";
if (system $ppad_deffiltopts) {
warn "Could not set \"DefFiltOpts\" entry for " .
"the queue \"$config->{'queue'}\"!\n";
}
} else {
die "Could not set PPD for the queue \"$config->{'queue'}\"!\n";
}
} else {
my $ppad_ppd = "$sysdeps->{'ppr-ppad'} ppd " .
"\"$config->{'queue'}\" \"$ppdfile\" 2> /dev/null";
if (!system $ppad_ppd) {
# Automatic input tray selection not activated by default,
# because the feature requires manual choice of the paper types
# in the trays and other spoolers than PPR do not have automatic
# paper tray selection. In addition "ppop media <queue>" is
# broken for printers with a high number of input trays in their
# PPD files.
#my $ppad_bins = "$sysdeps->{'ppr-ppad'} bins ppd " .
#"\"$config->{'queue'}\"";
#if (system $ppad_bins) {
#warn "Could not set paper input trays for the " .
#"queue \"$config->{'queue'}\"!\n";
#}
my $ppad_deffiltopts = "$sysdeps->{'ppr-ppad'} " .
"deffiltopts \"$config->{'queue'}\" 2> /dev/null";
if (system $ppad_deffiltopts) {
warn "Could not set \"DefFiltOpts\" entry for the " .
"queue \"$config->{'queue'}\"!\n";
}
} else {
die "Could not set PPD for the queue \"$config->{'queue'}\"!\n";
}
}
if ($rawqueue) {
# If we have a raw queue, delete the PPD file if there is still
# one from a former queue.
unlink "$ppdfile"
if (-f "$ppdfile");
} else {
# Clean up "Switchset" entry
my @switchset = split('|', $entry->{'Switchset'});
my @newswitchset = ();
for my $option (@switchset) {
if (!(($option =~ /^F\s*\*([^\*\s=:]+)\s+([^\*\s=:]+)\s*$/) ||
($option =~ /^F\s*([^\*\s=:]+)\s*=\s*([^\*\s=:]+)\s*$/) ||
($option =~ /^F\s*\*([^\*\s=:]+)\s*$/) ||
($option =~ /^F\s*([^\*\s=:]+)\s*$/))) {
# The option is not a PPD option, keep it.
# PPD options are incorporated in the PPD file now and so
# they can be dropped in the "Switchset".
if ($option =~ /^\s*(\S)(.*)$/) {
push (@newswitchset, "-$1 \"$2\"");
}
}
}
my $ppad_switchset = "$sysdeps->{'ppr-ppad'} switchset " .
"\"$config->{'queue'}\" " . join (' ', @newswitchset);
if (system $ppad_switchset) {
warn "Could not set switchset for the queue " .
"\"$config->{'queue'}\"!\n";
}
# Check, if there is a PJL option and set the "Jobbreak" to "none"
# because otherwise there is a Ctrl+D between the PJL frame added
# by foomatic-rip and the PostScript job. This breaks printing of
# certain PS files as the CUPS test page.
my $pjloption = 0;
for my $arg (@{$db->{'dat'}->{'args'}}) {
if ($arg->{'style'} eq "J") {
$pjloption = 1;
last;
}
}
if ($pjloption) {
my $ppad_jobbreak = "$sysdeps->{'ppr-ppad'} jobbreak " .
"\"$config->{'queue'}\" none";
if (system $ppad_jobbreak) {
warn "Could not set \"Jobbreak\" entry for the " .
"queue \"$config->{'queue'}\"!\n";
}
}
}
return 1;
}
sub default_ppr {
my ($config) = $_[0];
# The default printer under PPR is the printer named "default". To be
# able to easily switch the default printer we set up a printer group
# named "default" containing the chosen default printer as its only
# member. If there is already a printer called "default", we rename it.
my $name = $config->{'queue'};
my $printrc = load_ppr_printers_conf();
my $printerfound = 0;
for my $p (@{$printrc}) {
if ($p->{'name'} eq $name) {
$printerfound = 1;
}
# Rename a printer whose name is 'default'
if ($p->{'name'} eq 'default') {
# Search for a free name
my $i = 0;
my $namefound = 0;
my $newname = "";
while(!$namefound) {
my $pp;
my $nameinuse = 0;
for $pp (@{$printrc}) {
if (defined($pp->{'name'})) {
if ($pp->{'name'} eq "default$i") {
$nameinuse = 1;
$i++;
last;
}
}
}
$namefound = 1 - $nameinuse;
}
$newname = "default$i";
# If the printer we want to use as default printer has the
# name "default", we must use the new name as the member name
# in the default group.
if ($name eq "default") {
$name = $newname;
}
# Do the renaming
# Copy the queue ...
if (system("foomatic-configure -s ppr -n $newname -C default")){
die "Could not copy the queue \"default\" into the " .
"queue \"$newname\"!\n";
}
# ... and remove the original one
if (system("foomatic-configure -s ppr -n default -R")) {
die "Could not remove the queue \"default\"!\n";
}
warn "Renamed the printer\"default\" to \"$newname\"!\n";
}
}
# The desired default printer exists? Then make it the default
if ($printerfound) {
# Create a group named "default" with only this printer as member
my $ppad_group = "$sysdeps->{'ppr-ppad'} group members " .
"default \"$name\"";
if (system $ppad_group) {
warn "Could not create a group to make the queue \"$name\" " .
"the default!\n";
}
}
}
sub delete_ppr {
my ($config) = $_[0];
# This line deletes the old printer queue
my $queuedeleteline = "$sysdeps->{'ppr-ppad'} delete " .
"\"$config->{'queue'}\"";
# Do it!
system $queuedeleteline and
die "Unable to delete queue \"$config->{'queue'}\"!\n";
# Rename the PPD file
# PPD file name
my $ppdfile = sprintf('%s/ppr/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Rename old $ppdfile, if any
rename "$ppdfile", "$ppdfile.old"
if (-f "$ppdfile");
return 1;
}
sub query_ppr {
my ($config) = @_;
# User requests data of a printer/driver combo to see the options before
# installing a queue
if (($opt_P) && ((($config->{'driver'}) && ($config->{'printer'}) &&
($config->{'driver'} ne "raw")) || ($config->{'ppdfile'}))) {
if ($opt_n) {
my $olddatablob = load_ppr_datablob($opt_n);
print_perl_combo_data($config, $olddatablob);
} else {
print_perl_combo_data($config);
}
return;
}
my $i = $ARGV[0];
if (!defined($i)) {$i = 0;}
my $pconf = load_ppr_printers_conf();
if (defined($opt_r)) {$opt_r = undef;}
my $p;
if (!$opt_P) {
print "<queues>\n";
}
# Query the default printer
my $default;
if (!defined($config->{'queue'})) {
for $p (@{$pconf}) {
if ($p->{'default'}) {
$default = $p->{'name'};
if (!$opt_P) {
print "<defaultqueue>$p->{'name'}</defaultqueue>\n";
}
last;
}
}
}
for $p (@{$pconf}) {
# were we invoked for only one queue?
next if (defined($config->{'queue'})
and $config->{'queue'} ne $p->{'name'});
# load the queue data
$db->{'dat'} = load_ppr_datablob($p->{'name'});
# extract the queue data block
my $c = $db->{'dat'}{'queuedata'};
if ($opt_P) {
if ($p->{'name'} eq $default) {
$db->{'dat'}{'queuedata'}{'default'} = 1;
} else {
$db->{'dat'}{'queuedata'}{'default'} = 0;
}
$db->{'dat'}{'queuedata'}{'remote'} = 0;
my $asciidata = $db->getascii();
$asciidata =~ s/\$VAR1/\$QUEUES[$i]/g;
print $asciidata;
$i ++;
} else {
# and get it to standard output
dump_config($c);
}
}
if (!$opt_P) {
print "</queues>\n";
}
return;
}
### Queue manipulation functions for direct, spooler-less printing
sub setup_direct {
my ($config) = $_[0];
# Read the previous config file
my $pconfig = load_direct_config();
my ($entry, $reconf, $p);
for $p (@{$pconfig}) {
if ($p->{'name'} eq $config->{'queue'}) {
$entry = $p;
$reconf = 1;
last;
use Data::Dumper;
print "Reconfigure of ", Dumper($p);
}
}
# PPD file name
my $ppdfile = sprintf('%s/direct/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Get the data from the former queue if we reconfigure or copy a queue
# do also some checking of the user-supplied parameters
my ($rawqueue, $newfoomaticdata, $makemodel) =
getoldqueuedata($config, $reconf);
# Set the printer queue name
$entry->{'name'} = $config->{'queue'};
# Use manufacturer and model as description when no description is
# provided
if (defined($config->{'desc'})) {
$entry->{'desc'} = $config->{'desc'};
} else {
# Before we overwrite the description field with manufacturer
# and model, check if there is some old contents
my( $olddesc );
if (($reconf) && ($entry->{'desc'})) {
$olddesc = $entry->{'desc'};
}
if (!$olddesc) {
$entry->{'desc'} = "$makemodel";
}
}
# Fill in the "location" field if something for it is provided.
if (defined($config->{'loc'})) {
$entry->{'loc'} = $config->{'loc'};
}
# If the printing jobs should not be passed to standard output, put the
# command line into $postpipe (for example for Socket, Samba, parallel
# port ...)
my $postpipe = "";
if ((!$reconf) or ($config->{'connect'})) {
# Set up connection type
# All URIs ("-c" option) have the same syntax as URIs in CUPS ("-v"
# option of "lpadmin").
if ($config->{'connect'} =~ m!^(file|usb|parallel|serial):(.*)!) {
# Local printer or printing to a file
my $file = $2;
if ($config->{'connect'} =~ m!^usb://!) {
# Queue with printer-bound USB URI transferred from CUPS,
# as spooler-less printing does not support these URIs,
# translate it back to a standard USB device URI
$file = cups_usb_printer_uri_to_device_uri($file);
}
if (! -e $file) {
warn "The device or file $file doesn't exist? " .
"Working anyway.\n";
}
if (($file =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($file =~ m!^/dev/ptal-printd/(.+)$!) ||
($file =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate URI for ptal-printd to postpipe using the
# "ptal-connect" command
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$postpipe = "$sysdeps->{'ptal-connect'} $devname -print";
} else {
$postpipe = "$sysdeps->{'cat'} > $file";
}
} elsif ($config->{'connect'} =~ m!^ptal://?([^/].*)$!) {
# HPOJ MLC protocol
my $devname = $1;
$postpipe = "$sysdeps->{'ptal-connect'} $devname -print";
} elsif ($config->{'connect'} =~ m!^mtink:/(.+)$!) {
# Printing through "mtinkd"
$postpipe = "$sysdeps->{'cat'} > $sysdeps->{'mtink-pipes'}/$1";
} elsif ($config->{'connect'} =~ m!^lpd://([^/]+)/([^/]+)$!) {
# Remote LPD
my $remhost = $1;
my $remqueue = $2;
$postpipe = "$sysdeps->{'rlpr'} -q -h -P $remqueue\@$remhost";
} elsif ($config->{'connect'} =~
m!^socket://([^/:]+):([0-9]+)/?$!){
# Socket (AppSocket/HP JetDirect)
my $remhost = $1;
my $remport = $2;
$postpipe = "$sysdeps->{'nc'} -w 1 $remhost $remport";
} elsif ($config->{'connect'} =~ m!^smb://(.*)$!) {
# SMB (Printer on Windows server)
my $parameters = $1;
# Get the user's login and password from the URI
my $smbuser = "";
my $smbpassword = "";
if ($parameters =~ m!([^@]*)@([^@]+)!) {
my $login = $1;
$parameters = $2;
if ($login =~ m!([^:]*):([^:]*)!) {
$smbuser = $1;
$smbpassword = $2;
} else {
$smbuser = $login;
$smbpassword = "";
}
} else {
$smbuser = "GUEST";
$smbpassword = "";
}
# Get the workgroup, server, and share name
my $workgroup = "";
my $smbserver = "";
my $smbshare = "";
if ($parameters =~ m!([^/]*)/([^/]+)/([^/]+)$!) {
$workgroup = $1;
$smbserver = $2;
$smbshare = $3;
} elsif ($parameters =~ m!([^/]+)/([^/]+)$!) {
$workgroup = "";
$smbserver = $1;
$smbshare = $2;
} else {
die "The \"smb://\" URI must at least contain the " .
"server name and the share name!\n";
}
# Set up the command line for printing on the SMB server
$postpipe = "$sysdeps->{'smbclient'} \"//$smbserver/$smbshare\"";
if ($smbpassword ne "") {
warn("WARNING: smbclient password is visible in PPD file\n");
$postpipe .= " $smbpassword";
}
if ($smbuser ne "") {$postpipe .= " -U $smbuser";}
if ($workgroup ne "") {$postpipe .= " -W $workgroup";}
$postpipe .= " -N -P -c 'print -' ";
} elsif ($config->{'connect'} =~ m!^ncp://(.*)$!) {
my $parameters = $1;
# Get the user's login and password from the URI
my $ncpuser = "";
my $ncppassword = "";
if ($parameters =~ m!([^@]*)@([^@]+)!) {
my $login = $1;
$parameters = $2;
if ($login =~ m!([^:]*):([^:]*)!) {
$ncpuser = $1;
$ncppassword = $2;
} else {
$ncpuser = $login;
$ncppassword = "";
}
} else {
$ncpuser = "";
$ncppassword = "";
}
# Get the server and share name
my $ncpserver = "";
my $ncpqueue = "";
if ($parameters =~ m!([^/]+)/([^/]+)$!) {
$ncpserver = $1;
$ncpqueue = $2;
} else {
die "The \"ncp://\" URI must at least contain the server " .
"name and the queue name!\n";
}
# Set up the command line for printing on the Netware server
$postpipe = "$sysdeps->{'nprint'} -S $ncpserver";
if ($ncpuser ne "") {
$postpipe .= " -U $ncpuser";
if ($ncppassword ne "") {
warn("WARNING: ncp password is visible in PPD file\n");
$postpipe .= " -P $ncppassword";
} else {
$postpipe .= " -n";
}
}
$postpipe .= " -q $ncpqueue -N - 2>/dev/null";
} elsif ($config->{'connect'} =~ m!^postpipe:(.*)$!) {
# Pipe output into a command
$postpipe = $1;
} elsif ($config->{'connect'} =~ m!^stdout!) {
$postpipe = "";
} elsif ($config->{'connect'}) {
die ("The URI \"$config->{'connect'}\" is not supported for " .
"spooler-less printing or you have\nmistyped.\n");
} else {
die "You must specify a connection with -c.\n";
}
# Put $postpipe into the data structure, so that it will be
# inserted into the PPD file
if ($postpipe ne "") {
$postpipe = "| $postpipe";
$db->{'dat'}{'postpipe'} = $postpipe;
} else {
undef $db->{'dat'}{'postpipe'};
}
} else {
# Keep previous connection type
# Use previous $postpipe
if (defined($db->{'dat'}{'postpipe'})) {
$postpipe = $db->{'dat'}{'postpipe'};
}
}
# Various file setup
mkdir $sysdeps->{'foo-etc'}, 0755;
mkdir $sysdeps->{'foo-etc'} . "/direct", 0755;
# Add to the config file if a new entry
if (!$reconf) {
push(@{$pconfig}, $entry);
}
# Generate/write the PPD file
writeppdfile($config, $ppdfile, $rawqueue, $newfoomaticdata);
# Write back /etc/foomatic/direct/.config
my $pconfigname = $sysdeps->{'direct-config'};
rename $pconfigname, "$pconfigname.old";
open PCONFIG, "> $pconfigname" or die "Cannot write $pconfigname!\n";
print PCONFIG dump_direct_config($pconfig);
close PCONFIG;
chmod 0644, $pconfigname;
return 1;
}
sub default_direct {
my ($config) = $_[0];
my $name = $config->{'queue'};
my $pconfig = load_direct_config();
# Modify the "default" fields of the printers appropriately
for (@{$pconfig}) {
$_->{'default'} = ($_->{'name'} eq $name);
}
my @newpconfig = dump_direct_config($pconfig);
my $pconfigname = $sysdeps->{'direct-config'};
rename $pconfigname, "$pconfigname.old";
open PCONFIG, "> $pconfigname" or die "Cannot write $pconfigname!\n";
print PCONFIG @newpconfig;
close PCONFIG;
chmod 0644, $pconfigname;
return 1;
}
sub delete_direct {
my ($config) = $_[0];
my $name = $config->{'queue'};
my $pconfig = load_direct_config();
# Overtake all entries except the one of the deleted printer to the
# new config file
my @newconf;
for (@{$pconfig}) {
push (@newconf, $_)
unless ($_->{'name'} eq $name);
}
my @newpconfig = dump_direct_config(\@newconf);
my $pconfigname = $sysdeps->{'direct-config'};
rename $pconfigname, "$pconfigname.old";
open PCONFIG, "> $pconfigname" or die "Cannot write $pconfigname!\n";
print PCONFIG @newpconfig;
close PCONFIG;
chmod 0644, $pconfigname;
# PPD file name
my $ppdfile = sprintf('%s/direct/%s.ppd',
$sysdeps->{'foo-etc'},
$config->{'queue'});
# Rename old $ppdfile, if any
rename $ppdfile, "$ppdfile.old"
if (-f $ppdfile);
return 1;
}
sub query_direct {
my ($config) = @_;
# User requests data of a printer/driver combo to see the options before
# installing a queue
if (($opt_P) && ((($config->{'driver'}) && ($config->{'printer'}) &&
($config->{'driver'} ne "raw")) || ($config->{'ppdfile'}))) {
if ($opt_n) {
my $olddatablob = load_direct_datablob($opt_n);
print_perl_combo_data($config, $olddatablob);
} else {
print_perl_combo_data($config);
}
return;
}
my $i = $ARGV[0];
if (!defined($i)) {$i = 0;}
my $pconf = load_direct_config();
if (defined($opt_r)) {$opt_r = undef;}
my $p;
if (!$opt_P) {
print "<queues>\n";
}
# Query the default printer
my $default;
if (!defined($config->{'queue'})) {
for $p (@{$pconf}) {
if ($p->{'default'}) {
$default = $p->{'name'};
if (!$opt_P) {
print "<defaultqueue>$p->{'name'}</defaultqueue>\n";
}
last;
}
}
}
for $p (@{$pconf}) {
# were we invoked for only one queue?
next if (defined($config->{'queue'})
and $config->{'queue'} ne $p->{'name'});
# load the queue data
$db->{'dat'} = load_direct_datablob($p->{'name'});
# extract the queue data block
my $c = $db->{'dat'}{'queuedata'};
if ($opt_P) {
if ($p->{'name'} eq $default) {
$db->{'dat'}{'queuedata'}{'default'} = 1;
} else {
$db->{'dat'}{'queuedata'}{'default'} = 0;
}
$db->{'dat'}{'queuedata'}{'remote'} = 0;
my $asciidata = $db->getascii();
$asciidata =~ s/\$VAR1/\$QUEUES[$i]/g;
print $asciidata;
$i ++;
} else {
# and get it to standard output
dump_config($c);
}
}
if (!$opt_P) {
print "</queues>\n";
}
return;
}
### Functions used by the queue manipulation functions from above
sub dump_config {
my $c = $_[0];
print
sprintf("<queue foomatic=\"%d\" spooler=\"%s\">\n",
($c->{'foomatic'} ? 1 : 0),
$c->{'spooler'}),
_tag('name',$c->{'queue'}),
_tag('printer',$c->{'printer'}),
_tag('driver',$c->{'driver'}),
_tag('connect',$c->{'connect'}),
_tag('location',$c->{'loc'}),
_tag('description',$c->{'desc'}),
($c->{'spooler'} eq "cups" ?
(_tag('dontdisable',$c->{'dd'}),
_tag('attempts',$c->{'att'}),
_tag('delay',$c->{'delay'}),
(defined($c->{'quotaperiod'}) ?
_tag('quotaperiod',$c->{'quotaperiod'}) : ()),
(defined($c->{'pagelimit'}) ?
_tag('pagelimit',$c->{'pagelimit'}) : ()),
(defined($c->{'klimit'}) ?
_tag('klimit',$c->{'klimit'}) : ()),
(defined($c->{'laststatechange'}) ?
_tag('laststatechange',$c->{'laststatechange'}) : ()),
(defined($c->{'shared'}) ?
_tag('shared',$c->{'shared'}) : ()),
(defined($c->{'operationpolicy'}) ?
_tag('operationpolicy',$c->{'operationpolicy'}) : ()),
(defined($c->{'errorpolicy'}) ?
_tag('errorpolicy',$c->{'errorpolicy'}) : ())) : ()),
"</queue>\n";
return;
}
sub _tag {
my ($t, $v) = @_;
return '' if !defined($v);
$v =~ s!\&!\&\;!g;
$v =~ s!\<!\<\;!g;
return " <$t>$v</$t>\n";
}
sub dump_lpd_printcap {
my ($config, $pcap )= @_;
my @retval;
my $item;
my $backslash = "\\";
$backslash = "" if $config->{'spooler'} eq 'lprng';
for $item (@{$pcap}) {
for (@{$item->{'comments'}}) {
push (@retval, "$_\n");
}
if (defined($item->{'names'})) {
map { $_ = '' if not defined $_; } @{$item->{'names'}};
push (@retval, (join('|', @{$item->{'names'}}) . ":${backslash}\n"));
}
for (keys(%{$item->{'str'}})) {
# special case of 'tc' items, as there can be more than one
if ($_ =~ /^tc\d+$/) {
push (@retval,
sprintf(" :tc=%s:${backslash}\n", $item->{'str'}{$_}));
} else {
push (@retval,
sprintf(" :$_=%s:${backslash}\n", $item->{'str'}{$_}));
}
}
for (keys(%{$item->{'bool'}})) {
if ($item->{'bool'}{$_}) {
push (@retval, " :$_:${backslash}\n");
}
}
for (keys(%{$item->{'num'}})) {
push (@retval,
sprintf(" :$_#%s:${backslash}\n", $item->{'num'}{$_}));
}
if( $backslash ){
my $lastline = pop(@retval);
$lastline =~ s!:\\!:!;
push (@retval, $lastline);
}
}
print "PRINTCAP (spooler '" . $config->{'spooler'} . "') " . Dumper(\@retval) . "\n" if $debug;
return @retval;
}
sub load_lpd_printcap {
# list-o-printers, each with comments
open PCAP, $sysdeps->{'lpd-pcap'} or die "Cannot read printcap file!\n";
my $pcap = join('', <PCAP>);
close PCAP;
print "PC '$pcap'\n" if $debug;
# die( "Cannot currently parse lprng style printcaps created by " .
# "lprngtool!\n" .
# "See the BUGS section in the manpage for details.\n")
# if $pcap =~ m/\n\s*(:.*[^\\]\n\s*:)/m;
# watch out for comments with \ at end of line - ignore \
$pcap =~ s!^(\s*\#.*\\)$!${1}MEMEMEM!gm;
# now we join lines with \ at end
$pcap =~ s!\\\n!!gms;
# remove \ in comment lines
$pcap =~ s!\\MEMEMEM!\\!g;
print "AFTER '$pcap'\n" if $debug;
my (@comment, @items, @comments_in_pc_entry);
my ($pline, $pcentry);
$pcentry = "";
for $pline (split('\n',$pcap)) {
$pline =~ s/^\s+//;
print "LINE '$pline', pcentry '$pcentry'\n" if $debug;
next if $pline eq "";
if ($pline =~ m!^\#!) {
if( $pcentry ){
push (@comments_in_pc_entry, $pline);
} else {
push (@comment, $pline);
}
} elsif ($pline =~ m!^:!) {
push( @comment, @comments_in_pc_entry );
@comments_in_pc_entry = ();
if( $pcentry ne "" ){
$pcentry .= $pline;
} else {
die( "bad printcap entry at '$pline'" );
}
} elsif( $pcentry ne "" ){
push (@items, { 'itemstr' => $pcentry,
'comments' => [ @comment ] });
@comment = @comments_in_pc_entry;
@comments_in_pc_entry = ();
$pcentry = $pline;
} else {
$pcentry = $pline;
}
}
if( $pcentry ){
push( @comment, @comments_in_pc_entry );
@comments_in_pc_entry = ();
push (@items, { 'itemstr' => $pcentry,
'comments' => [ @comment ] });
@comment = ();
}
# Trailing comments get stuck on as empty item later...
print "Printcap:\n" . Dumper(\@items ) if $debug;
my $p;
for $p (@items) {
my $item;
my $first = 1;
my $tci = 0;
for $item (split(/:\s*/, $p->{'itemstr'})) {
next if $item =~ m!^\s*$!;
if ($first) {
my $name;
for $name (split('\|',$item)) {
$name =~ s!\s*(.+)\s*!$1!;
push (@{$p->{'names'}}, $name);
}
$first = 0;
} else {
if ($item =~ m!^([^=]*)=(.+)!) {
# special case of 'tc' items, as there can be more
# than one
if ($1 eq 'tc') { $p->{'str'}{"tc$tci"} = $2; $tci++; }
else { $p->{'str'}{$1} = $2; }
} elsif ($item =~ m!^([^\#]*)\#(.+)!) {
$p->{'num'}{$1} = $2;
} elsif ($item =~ m!^([^\@]*)\@?!) {
$p->{'bool'}{$1} = 1;
}
}
}
}
# Trailing comments from way above...
if (scalar(@comment)) {
push (@items, {'comments' => [ @comment ]});
}
return \@items;
}
sub load_cups_printersconf {
# list-o-printers
my @items = ();
my $itemshash = {};
if ($< == 0) {
# Get info from /etc/cups/printers.conf, works only as "root" and
# with locally defined printers
my @pconf = ();
if (open PCONF, $sysdeps->{'cups-pconf'}) {
@pconf = <PCONF>;
close PCONF;
}
my $line;
my $p = {};
my $linecount = 0;
for $line (@pconf) {
$linecount ++;
if (!($line =~ m!^\s*\#!) && (!($line =~ m!^\s*$!))) {
if ($line =~ m!^\s*<(.*)Printer\s+([^\s>]+)>\s*$!) {
# Beginning of new <Printer ...> block
$p->{'name'} = $2;
$p->{'default'} = ($1 eq "Default");
} elsif ($line =~ m!^\s*</Printer>\s*$!) {
# End of <Printer ...> block
push (@items, $p);
$itemshash->{$p->{name}} = $#items;
$p = {};
} elsif (defined($p->{'name'})) {
# Inside <Printer ...> block
if (($line =~ m!^\s*(\S+)\s+(\S.*)$!) and
($1 ne '')) {$p->{$1} = $2};
} else {
# Outside <Printer ...> block
die "Line $linecount in $sysdeps->{'cups-pconf'} " .
"invalid!\n";
}
}
}
}
if (($< != 0) || (($opt_r) && (($opt_Q) || ($opt_P)))) {
# Get info with the "lpstat" command, works for normal users and for
# remote printers.
open LPSTAT, "$sysdeps->{'cups-lpstat'} -l -d -p -v |" or
die "Cannot execute \"lpstat\".\n";
my @lpstat = <LPSTAT>;
close LPSTAT;
my $line;
my $linecount = 0;
my $defaultprinter = '';
my $currentitem = -1;
for $line (@lpstat) {
chomp ($line);
$linecount ++;
if (!($line =~ m!^\s*$!)) {
if ($line =~
m!^\s*system\s+default\s+destination:\s+(\S+)\s*$!) {
# Default printer
$defaultprinter = $1;
} elsif ($line =~ m!^printer\s+(\S+)\s+(\S.*)$!) {
# Beginning of new printer's entry
my $name = $1;
my $state = $2;
$state =~ s/\s+-$//;
if (!defined($itemshash->{$name})) {
push(@items, {});
$itemshash->{$name} = $#items;
# If we are root and didn't see this entry
# in /etc/cups/printers.conf, this printer
# is remotely defined
if ($< == 0) {
$items[$itemshash->{$name}]{'remote'} = 1;
}
}
$currentitem = $itemshash->{$name};
$items[$currentitem]{'name'} ||= $name;
$items[$currentitem]{'State'} ||= $state;
$items[$currentitem]{'default'} =
($name eq $defaultprinter);
} elsif ($line =~ m!^\s+Description:\s+(\S.*)$!) {
# Description field
if ($currentitem != -1) {
$items[$currentitem]{'Info'} ||= $1;
}
} elsif ($line =~ m!^\s+Location:\s+(\S.*)$!) {
# Location field
if ($currentitem != -1) {
$items[$currentitem]{'Location'} ||= $1;
}
} elsif ($line =~ m!^\s+Connection:\s+remote!) {
# Remote printer, only keep it when the "-r" option is
# given
if (!$opt_r) {
# "delete" does not work on arrays with Perl 5.0.x
# Thanks to Olaf Till (i7tiol@t-online.de) who
# contributed this fix
splice(@items, $currentitem, 1);
#delete($items[$currentitem]);
$currentitem = -1;
} else {
if ($currentitem != -1) {
$items[$currentitem]{'remote'} = 1;
}
}
} elsif ($line =~ m!^device\s+for\s+(\S+):\s+(\S.*)$!) {
# "device for ..." line, extract URI
my $name = $1;
my $uri = $2;
if (defined($itemshash->{$name})) {
if ($uri !~ /:/) {$uri = "file:" . $uri};
$currentitem = $itemshash->{$name};
if (($currentitem <= $#items) &&
($items[$currentitem]{'name'} eq $name)) {
$items[$currentitem]{'DeviceURI'} ||= $uri;
}
}
}
}
}
}
return \@items;
}
sub dump_pdq_printrc {
my $printrc = $_[0];
my @retval;
my $item;
for $item (@{$printrc}) {
if (defined($item->{'name'})) {
# $item is a "printer" block
push (@retval, "printer \"$item->{'name'}\" \{\n");
for my $key (keys(%{$item})) {
if (($key ne 'name') && ($key ne 'others')) {
push (@retval, "\t$key $item->{$key}\n");
}
}
push (@retval, "\}\n");
} elsif (defined($item->{'others'})) {
# $item is not a "printer" block
push (@retval, $item->{'others'});
}
}
# Check whether there is a already a 'try_include "/etc/foomatic/pdq/*"'
# line in the config file
if (!(join("", @retval) =~
m!^\s*try_include\s*\"$sysdeps->{'foo-etc'}/pdq/driverdescr/\*\"\s*$!m)) {
splice(@retval,0,0,"# Line inserted by $progname\ntry_include " .
"\"$sysdeps->{'foo-etc'}/pdq/driverdescr/*\"\n\n");
}
# De-activate old line from Foomatic 2.0.x
($_ =~ s!^\s*try_include\s*\"$sysdeps->{'foo-etc'}/pdq/\*\"\s*$!\#$&!m)
foreach @retval;
return @retval;
}
sub load_pdq_printrc {
# list-o-printers, with storage of non-printer-specific lines
open PRINTRC, $sysdeps->{'pdq-printrc'} or
die "Cannot read printrc file!\n";
my @printrc = <PRINTRC>;
close PRINTRC;
my @items;
my @others;
my $line;
my $p;
my $linecount = 0;
my $inprinterblock = 0;
my $nonprinterlines = 0;
for $line (@printrc) {
$linecount ++;
if ($line =~ m!^\s*printer\s+\"(.+)\"\s*{\s*$!) {
if ($inprinterblock == 1) {
die "New printer block started without previous one " .
"being closed!\nLine $linecount in " .
"$sysdeps->{'pdq-printrc'}.\n";
}
# Beginning of new "printer" block
# Store all non-printer-block stuff at first
if ($nonprinterlines == 1) {
push (@items, {'others' => join ("", @others )});
$nonprinterlines = 0;
@others = ();
}
# Read printer block name
$inprinterblock = 1;
$p->{'name'} = $1;
} elsif ($inprinterblock == 1) {
# Inside "printer" block
if ($line =~ m!^\s*}\s*$!) {
# End of "printer" block
$inprinterblock = 0;
push (@items, $p);
$p = {};
} elsif ($line =~ m!^\s*(\S+)\s*(\S+.*)$!) {
$p->{$1} = $2;
} elsif ((!($line =~ m!^\s*\#!)) &&
(!($line =~ m!^\s*$!))) {
die "Line $linecount in $sysdeps->{'pdq-printrc'} " .
"invalid!\n";
}
} else {
# Outside "printer" block
push(@others, $line);
$nonprinterlines = 1;
}
}
# Trailing non-printer lines get stuck on as empty item
if ($nonprinterlines == 1) {
my $lines = join ("", @others);
# Make sure that the last line line ends with a newline character
if (!($lines =~ m!\n$!s)) {$lines .= "\n";}
push (@items, {'others' => $lines});
}
return \@items;
}
sub load_ppr_printers_conf {
# Check whether there is a group named "default" to see what is the
# default printer.
my $defaultfromgroup = " ";
if (open SHOWDEFAULTGROUP,
"$sysdeps->{'ppr-ppad'} group show default 2>/dev/null |"){
for my $line (<SHOWDEFAULTGROUP>) {
chomp $line;
if ($line =~ /\s*Members:\s*([^\s,]+)\s*$/) {
$defaultfromgroup = $1;
last;
}
}
close SHOWDEFAULTGROUP;
}
# list-o-printers
my @items = ();
my $itemshash = {};
if ($< == 0) {
# Get info from /etc/ppr/printers/<queue name>, works only as
# "root"
opendir PCONFDIR, "$sysdeps->{'ppr-etc'}/printers" or
die "Cannot read $sysdeps->{'ppr-etc'}/printers directory!\n";
my $name;
while ($name = readdir(PCONFDIR)) {
# Do not consider "." and ".." as a printer queue
next if ($name =~ /^\./);
my $line;
my $p = {};
$p->{'name'} = $name;
$p->{'default'} = (($name eq "default") ||
($name eq $defaultfromgroup));
@{$p->{'Bins'}} = ();
my $linecount = 0;
open PCONFFILE, "$sysdeps->{'ppr-etc'}/printers/$name" or
die "Cannot read $sysdeps->{'ppr-etc'}/printers/$name!\n";
for my $line (<PCONFFILE>) {
chomp $line;
$linecount ++;
if (!($line =~ m!^\s*\#!) && (!($line =~ m!^\s*$!))) {
if (($line =~ m!^\s*([^\s:]+)\s*:\s*(\S.*)$!) ||
($line =~ m!^\s*([^\s:]+)\s*:\s*()$!)) {
# <keyword>: <value1> <value2> ...
my $keyword = $1;
my $values = $2;
if (($values) && ($values ne "")) {
# If the value is enclosed in double quotes,
# remove the quotes
$values =~ s/^\"(.*)\"$/$1/;
if ($keyword eq "Bin") {
push (@{$p->{'Bins'}}, $values);
} else {
$p->{$keyword} = $values;
}
}
} else {
warn "Line $linecount in " .
"$sysdeps->{'ppr-etc'}/printers/$name " .
"corrupted:\n $line\n";
}
}
}
close PCONFFILE;
push (@items, $p);
$itemshash->{$p->{'name'}} = $#items;
}
}
if ($< != 0) {
# Get info with the "ppop"/"ppad" commands, works for normal users,
# but needs installed and running PPR printing system
open PPOP_DEST, "$sysdeps->{'ppr-ppop'} destination all |" or
die "Cannot execute \"ppop\".\n";
my @ppop_dest = <PPOP_DEST>;
close PPOP_DEST;
my $line;
my $linecount = 0;
my $currentitem = -1;
for $line (@ppop_dest) {
chomp ($line);
$linecount ++;
if (($line !~ m!^\s*-+\s*$!) &&
($line !~ m!^\s*Destination\s+Type\s+Status\s+Charge\s*$!)){
if ($line =~ m!^\s*(\S+)\s+printer!) {
my $name = $1;
open PPAD_SHOW,"$sysdeps->{'ppr-ppad'} show $name |" or
die "Cannot execute \"ppad\".\n";
my $lcount = 0;
if (!defined($itemshash->{$name})) {
push(@items, {});
$itemshash->{$name} = $#items;
#print Dumper($itemshash);
}
$currentitem = $itemshash->{$name};
$items[$currentitem]{'name'} ||= $name;
$items[$currentitem]{'default'} =
(($name eq "default") ||
($name eq $defaultfromgroup));
for my $line (<PPAD_SHOW>) {
chomp $line;
$lcount ++;
if ((!($line =~ m!^\s*\#!)) &&
(!($line =~ m!^\s*$!))) {
if ($line =~
m!^\s*([^\s:][^:]*)\s*:\s*(.*)$!) {
# <keyword>: <value1> <value2> ...
my $keyword = $1;
my $values = $2;
if (($values) && ($values ne "")) {
# If the value is enclosed in double
# quotes, remove the quotes
$values =~ s/^\"(.*)\"$/$1/;
if ($keyword eq "Bins") {
@{$items[$currentitem]{'Bins'}} =
split(", ", $values);
} else {
if ($keyword eq "Switchset") {
$values =~ s/ -(\S) /\|$1/g;
$values =~ s/-(\S) /$1/g;
$values =~ s/\'//g;
$values =~ s/^|//g;
}
$items[$currentitem]{$keyword} =
$values;
}
}
} else {
warn "Line $lcount in \"ppad show " .
"$name\" corrupted:\n $line\n";
}
}
}
close PPAD_SHOW;
}
}
}
}
return \@items;
}
sub dump_direct_config {
my $config = $_[0];
my @retval;
my $defaultprinter = undef;
my $item;
for $item (@{$config}) {
if (defined($item->{'name'})) {
if (defined($item->{'desc'})) {
push (@retval, "$item->{'name'} desc:$item->{'desc'}\n");
}
if (defined($item->{'loc'})) {
push (@retval, "$item->{'name'} loc:$item->{'loc'}\n");
}
if ($item->{'default'}) {
$defaultprinter = $item->{'name'};
}
}
}
if (defined($defaultprinter)) {
unshift(@retval, "default: $defaultprinter\n");
}
return @retval;
}
sub load_direct_config {
# list-o-printers
my @items = ();
my $itemshash = {};
# Configured printers are represented by PPD files in /etc/foomatic/
opendir PCONFDIR, "$sysdeps->{'foo-etc'}/direct" or
die "Cannot read $sysdeps->{'foo-etc'}/direct directory!\n";
my $name;
while ($name = readdir(PCONFDIR)) {
# Files beginning with a dot or ending with a tilde are never
# printers
next if (($name =~ /^\./) || ($name =~ /~$/));
# Only ".ppd" files are printer descriptions.
next unless ($name =~ /\.ppd$/i);
$name =~ s/\.ppd$//i;
# Do not make two entries when there is both a ".ppd" AND ".PPD"
# file for the same printer name.
next if (defined($itemshash->{$name}));
my $p = {};
$p->{'name'} = $name;
push (@items, $p);
$itemshash->{$p->{'name'}} = $#items;
}
# Get additional info from /etc/foomatic/direct/.config (default
# printer, description, location
if (open CONFIG, "< $sysdeps->{'direct-config'}") {
while (my $line = <CONFIG>) {
chomp $line;
if ($line =~ /^default\s*:\s*([^:\s]+)\s*$/) {
my $currentitem = $itemshash->{$1};
$items[$currentitem]{'default'} = 1;
} elsif ($line =~ /^\s*([^:\s]+)\s+([^:\s]+)\s*:(.*)$/) {
my $currentitem = $itemshash->{$1};
$items[$currentitem]{$2} = $3;
}
}
close CONFIG;
}
return \@items;
}
sub cups_correct_ptal_uri {
# HPOJ 0.9 uses "ptal:..." URIs with one slash
# ("ptal:/mlc:usb:dj450") and the current CVS of HPOJ uses two
# slashes ("ptal://mlc:usb:dj450"). Correct the user-supplied URI
# according to what "lpinfo -v" reports.
my ($uri) = @_;
$uri =~ m!^ptal://?([^/].*)$!;
my $device = $1;
# PTAL URIs listed by "lpinfo -v"
open F, "$sysdeps->{'cups-lpinfo'} -v |" or return (@_);
while (my $line = <F>) {
chomp($line);
my $d = quotemeta($device);
if ($line =~ m!(ptal://?$d)$!) {
my $realdevice = $1;
close F;
return $realdevice;
}
}
close F;
# Nothing found, do not correct the input
return @_;
}
sub cups_generate_usb_device_lists {
# Generate two lists: One of the actual USB device files in the
# file system, another of the USB URIs listed by CUPS' "lpinfo -v"
# Actual devices
my @usbdevices;
for my $pattern ("/dev/usb/lp*", "/dev/usb/usblp*") {
open F, "ls -1 $pattern 2>/dev/null |" or next;
@usbdevices = sort { Foomatic::DB::normalizename($a) cmp
Foomatic::DB::normalizename($b) }
grep { chomp } <F>;
close F;
last if $#usbdevices >= 0;
}
return ([], []) if $#usbdevices < 0;
# USB URIs listed by "lpinfo -v"
open F, "$sysdeps->{'cups-lpinfo'} -v |" or return ([], []);
my @usburis = grep { s!^direct usb:!! and chomp } <F>;
close F;
return ([], []) if $#usburis < 0;
# Results
return (\@usbdevices, \@usburis);
}
sub cups_usb_device_uri_to_printer_uri {
# Transfer a device file name into a printer-bound CUPS URI for
# the printer currently connected
my ($device) = @_;
return $device if $device =~ m!^//!;
my @devicelists = cups_generate_usb_device_lists();
return $device if (($#{$devicelists[0]} < 0) ||
($#{$devicelists[1]} < 0));
for (my $i = 0; $i <= $#{$devicelists[0]}; $i ++) {
last if !$devicelists[1][$i];
if ($device eq $devicelists[0][$i]) {
return $devicelists[1][$i];
}
}
return $device;
}
sub cups_usb_printer_uri_to_device_uri {
# Transfer a device file name into a printer-bound CUPS URI for
# the printer currently connected
my ($device) = @_;
return $device if $device =~ m!^/[^/]!;
$device =~ s/ /\%20/g;
my @devicelists = cups_generate_usb_device_lists();
return $device if (($#{$devicelists[0]} < 0) ||
($#{$devicelists[1]} < 0));
for (my $i = 0; $i <= $#{$devicelists[1]}; $i ++) {
last if !$devicelists[0][$i];
if ($device eq $devicelists[1][$i]) {
return $devicelists[0][$i];
}
}
return $device;
}
sub load_datablob {
my ($spooler, $queue) = @_;
my $spoolersubdir;
my $datablob;
if (($spooler eq "lpd") ||
($spooler eq "lprng")) {
$datablob = load_lpd_datablob($queue);
$spoolersubdir = 'lpd';
} elsif ($spooler eq "cups") {
$datablob = load_cups_datablob($queue);
$spoolersubdir = 'cups';
} elsif ($spooler eq "pdq") {
$datablob = load_pdq_datablob($queue);
$spoolersubdir = 'pdq';
} elsif ($spooler eq "ppr") {
$datablob = load_ppr_datablob($queue);
$spoolersubdir = 'ppr';
} elsif ($spooler eq "direct") {
$datablob = load_direct_datablob($queue);
$spoolersubdir = 'direct';
} else {
die "Unsupported spooler: $spooler\n";
}
# Is the given queue a valid queue?
if (!$datablob) {
return undef;
}
return ($datablob);
}
sub load_lpd_datablob {
my ($queue) = $_[0];
# Load the PPD file
my $ppdfile = sprintf('%s/lpd/%s.ppd',
$sysdeps->{'foo-etc'},
$queue);
my $dat = ppdtoperl($ppdfile);
if (defined($dat)) {
$dat->{'ppdfile'} = $ppdfile;
}
my $postpipe = (defined($dat) ? $dat->{'postpipe'} : "");
# Get additional info from /etc/printcap
my $pcap = load_lpd_printcap();
my $p;
for $p (@{$pcap}) {
# enpty end entry for trailing comments
next if !defined($p->{'names'});
# Search for the correct queue
next if ($queue ne $p->{'names'}[0]);
# Collect values
my $c = {};
my $name = $c->{'queue'} = $p->{'names'}[0];
$c->{'desc'} = $p->{'names'}[1] if $p->{'names'}[1];
$c->{'loc'} = $p->{'names'}[3] if $p->{'names'}[3];
$c->{'foomatic'} = 0;
my $if = ($p->{'str'}{'if'} || "");
if ($if =~ m!foomatic-rip$!) {
$c->{'foomatic'} = 1;
$c->{'printer'} = $dat->{'id'};
$c->{'driver'} = $dat->{'driver'};
}
if (!$p->{'bool'}{'force_localhost'}) {
# LPD
$c->{'spooler'} = 'lpd';
} else {
# LPRng
$c->{'spooler'} = 'lprng';
}
# TODO Raw queue for LPD
# if (0 and $p->{'str'}{'if'} eq $file) { # Raw queue with $postpipe
# if (open FILE, "$file") {
# # The first line is #!/bin/sh
# $line = <FILE>;
# # The second line is a comment
# $line = <FILE>;
# # The remaining line(s) are the $postpipe
# $line = join('', <FILE>);
# chomp $line;
# $postpipe = "| $line";
# close FILE;
# }
# }
if (defined($postpipe)) {
if ($postpipe =~
m!^\s*\|\s*($sysdeps->{'cat'}|cat)\s+-?\s*>\s*([^\s]+)\s*$!) {
my $file = $2;
if (($file =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($file =~ m!^/dev/ptal-printd/(.+)$!) ||
($file =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate device for ptal-printd to ptal URI
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$c->{'connect'} = "ptal:/$devname";
} elsif (($file =~ m!^$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($file =~ m!^/var/mtink/(.+)$!)) {
# Translate device for mtinkd to mtink URI
$c->{'connect'} = "mtink:/$1";
} elsif ($file =~ m!usb!i) {
$c->{'connect'} = "usb:$file";
} elsif ($file =~ m!(tty|serial)!i) {
$c->{'connect'} = "serial:$file";
} elsif ($file =~ m!(lp[0-9]|parallel)!i) {
$c->{'connect'} = "parallel:$file";
} else {
$c->{'connect'} = "file:$file";
}
} elsif ($postpipe =~
m!^\s*\|\s*($sysdeps->{'ptal-connect'}|ptal-connect|ptal-print)\s+(-print\s+|)([^\s]+)(\s+-print|)\s*$!){
$c->{'connect'} = "ptal:/$3";
} elsif ($postpipe =~
m!^\s*\|\s*($sysdeps->{'nc'}|netcat|nc)\s+(-w\s*1\s+|)([^\s]+)\s+([^\s]+)\s*$!){
$c->{'connect'} = "socket://$3:$4";
} elsif ($postpipe =~
m!^\s*\|\s*$sysdeps->{'rlpr'}\s.*-P\s*([^\s\\\@]+)\@([^\s\\\@]+)\s*$!) {
$c->{'connect'} = "lpd://$2/$1";
} elsif ($postpipe =~
m!^.*\|\s*$sysdeps->{'smbclient'}\s+\"//([^/\s]+)/([^/\s]+)\"\s+(\S.*)$!s) {
my $servershare = "$1/$2";
my $parameters = $3;
my $password = "";
if ($parameters =~ m!^([^-]\S*)\s+(\S.*)$!) {
$password = $1;
$parameters = $2;
}
my $username = "";
if ($parameters =~ m!^-U\s+(\S*)\s+(\S.*)$!) {
$username = $1;
$parameters = $2;
}
my $workgroup = "";
if ($parameters =~ m!^-W\s+(\S*)\s+(\S.*)$!) {
$workgroup = "$1/";
}
my $identity = "";
if (($username eq "GUEST") && ($password eq "")) {
$identity = "";
} elsif (($username eq "") && ($password eq "")) {
$identity = "";
} elsif (($username ne "") && ($password eq "")) {
$identity = "$username\@";
} elsif (($username eq "") && ($password ne "")) {
$identity = ":$password\@";
} else {
$identity = "$username:$password\@";
}
$c->{'connect'} = "smb://$identity$workgroup$servershare";
} elsif ($postpipe =~
m!^\s*\|\s*$sysdeps->{'nprint'}\s+(\S.*)$!s) {
my $parameters = $1;
my $server = "";
if ($parameters =~ m!^-S\s+(\S*)\s+(\S.*)$!) {
$server = $1;
$parameters = $2;
}
my $username = "";
if ($parameters =~ m!^-U\s+(\S*)\s+(\S.*)$!) {
$username = $1;
$parameters = $2;
}
my $password = "";
if ($parameters =~ m!^-P\s+(\S*)\s+(\S.*)$!) {
$password = $1;
$parameters = $2;
}
if ($parameters =~ m!^-n\s+(\S.*)$!) {
$parameters = $1;
}
my $queue = "";
if ($parameters =~ m!^-q\s+(\S*)\s+(\S.*)$!) {
$queue = $1;
}
my $identity = "";
if (($username eq "") && ($password eq "")) {
$identity = "";
} elsif (($username ne "") && ($password eq "")) {
$identity = "$username\@";
} elsif (($username eq "") && ($password ne "")) {
$identity = ":$password\@";
} else {
$identity = "$username:$password\@";
}
$c->{'connect'} = "ncp://$identity$server/$queue";
} elsif( $postpipe ){
$postpipe =~ m!\s*\|\s*(\S.*)$!;
$c->{'connect'} = "postpipe:\"$1\"";
}
} else {
my $lp = $p->{'str'}{'lp'};
if (defined($lp) and $lp and $lp ne '/dev/null') {
if (($lp =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($lp =~ m!^/dev/ptal-printd/(.+)$!) ||
($lp =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate device for ptal-printd to ptal URI
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$c->{'connect'} = "ptal:/$devname";
} elsif (($lp =~ m!^$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($lp =~ m!^/var/mtink/(.+)$!)) {
# Translate device for mtinkd to mtink URI
$c->{'connect'} = "mtink:/$1";
} elsif ($lp =~ m!^\w+:!i) {
$c->{'connect'} = $lp;
} else {
$c->{'connect'} = "file:$lp";
}
}
my ($rm, $rp) = ($p->{'str'}{'rm'}, $p->{'str'}{'rp'});
if (defined($rm) and defined($rp)) {
$c->{'connect'} = "lpd://$rm/$rp";
}
}
$dat->{'queuedata'} = $c;
}
if (!defined($dat->{'queuedata'})) {$dat = undef};
return $dat;
}
sub load_cups_datablob {
my ($queue) = $_[0];
# Load the PPD file
my $ppdfile = sprintf('%s/ppd/%s.ppd',
$sysdeps->{'cups-etc'},
$queue);
#my $ppdfile = sprintf('%s/%s.ppd',
# $sysdeps->{'foo-etc'},
# $queue);
my $dat = ppdtoperl($ppdfile);
if (defined($dat)) {
$dat->{'ppdfile'} = $ppdfile;
}
# Get additional info from /etc/cups/printers.conf
my $pconf = load_cups_printersconf();
my $p;
for $p (@{$pconf}) {
# were we invoked for only one queue?
next if ($queue ne $p->{'name'});
# Collect values
my $c = {};
$c->{'spooler'} = 'cups';
$c->{'queue'} = $p->{'name'};
$c->{'foomatic'} = 0;
if (defined($dat->{'id'}) and defined($dat->{'driver'})) {
$c->{'foomatic'} = 1;
$c->{'printer'} = $dat->{'id'};
$c->{'driver'} = $dat->{'driver'};
}
$c->{'desc'} = $p->{'Info'};
$c->{'loc'} = $p->{'Location'};
my $uri = $p->{'DeviceURI'};
# Is the beh (Backend Error Handler) wrapper backend in use?
# If yes, read out its parameters and isolate the original URI.
if ($uri =~ m!^beh:/(\d+)/(\d+)/(\d+)/(\S+)$!) {
$c->{'dd'} = $1;
$c->{'att'} = $2;
$c->{'delay'} = $3;
$uri = $4;
} else {
$c->{'dd'} = 0;
$c->{'att'} = 1;
$c->{'delay'} = 30;
}
if (($uri =~ m!^file:$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($uri =~ m!^file:/dev/ptal-printd/(.+)$!) ||
($uri =~ m!^file:/var/run/ptal-printd/(.+)$!)) {
# Translate URI for ptal-printd to ptal URI
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$uri = "ptal:/$devname";
} elsif (($uri =~ m!^file:$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($uri =~ m!^file:/var/mtink/(.+)$!)) {
# Translate URI for mtinkd to mtink URI
$uri = "mtink:/$1";
}
$c->{'connect'} = $uri;
# CUPS-specific extra info
$c->{'quotaperiod'} = $p->{'QuotaPeriod'}
if defined($p->{'QuotaPeriod'});
$c->{'pagelimit'} = $p->{'PageLimit'}
if defined($p->{'PageLimit'});
$c->{'klimit'} = $p->{'KLimit'}
if defined($p->{'KLimit'});
# CUPS 1.2-specific settings
$c->{'laststatechange'} = $p->{'StateTime'}
if defined($p->{'StateTime'});
$c->{'shared'} = $p->{'Shared'}
if defined($p->{'Shared'});
$c->{'operationpolicy'} = $p->{'OpPolicy'}
if defined($p->{'OpPolicy'});
$c->{'errorpolicy'} = $p->{'ErrorPolicy'}
if defined($p->{'ErrorPolicy'});
$dat->{'queuedata'} = $c;
}
if (!defined($dat->{'queuedata'})) {$dat = undef};
return $dat;
}
sub load_pdq_datablob {
my ($queue) = $_[0];
# Load the PPD file
my $ppdfile = sprintf('%s/pdq/%s.ppd',
$sysdeps->{'foo-etc'},
$queue);
my $dat = ppdtoperl($ppdfile);
if (defined($dat)) {
$dat->{'ppdfile'} = $ppdfile;
}
if (defined($dat)) {
my $printrc = load_pdq_printrc();
my $p;
my $pdqopts;
my $pdqargs;
for $p (@{$printrc}) {
# Omit non-printer-block items
next if (!(defined($p->{'name'})));
# Search the current queue
next if ($queue ne $p->{'name'});
$pdqopts = $p->{'driver_opts'};
$pdqargs = $p->{'driver_args'};
}
my @printrcdefaults = split(",", $pdqopts);
push (@printrcdefaults, split(",", $pdqargs));
my $c;
@{$c->{'options'}} = ();
for my $option (@printrcdefaults) {
if ($option =~
m!^\s*\{?\s*\"(OPT_|)(.+?)\"\s*=\s*\"(.*)\"\s*\}?\s*$!) {
push (@{$c->{'options'}}, "$2=$3");
} elsif ($option =~
m!^\s*\{?\s*\"(OPT_|)([^_]+?)_(.+?)\"\s*\}?\s*$!) {
push (@{$c->{'options'}}, "$2=$3");
} elsif ($option =~ m!^\s*\{?\s*\"(OPT_|)(.+?)\"\s*\}?\s*$!) {
push (@{$c->{'options'}}, "$2");
}
}
set_default_options($c, $dat);
}
# Get additional info from printrc
my $printrc = load_pdq_printrc();
my $p;
for $p (@{$printrc}) {
# Omit non-printer-block items
next if (!(defined($p->{'name'})));
# Search for the appropriate queue
next if ($queue ne $p->{'name'});
my $c = {};
$c->{'spooler'} = 'pdq';
$c->{'queue'} = $p->{'name'};
$c->{'foomatic'} = 0;
if (defined($dat->{'id'}) and defined($dat->{'driver'})) {
$c->{'foomatic'} = 1;
$c->{'printer'} = $dat->{'id'};
$c->{'driver'} = $dat->{'driver'};
}
if (defined($p->{'model'})) {
my $desc = $p->{'model'};
$desc =~ s!^\"!!;
$desc =~ s!\"$!!;
if ($desc ne '') {$c->{'desc'} = $desc;}
}
if (defined($p->{'location'})) {
my $loc = $p->{'location'};
$loc =~ s!^\"!!;
$loc =~ s!\"$!!;
if ($loc ne '') {$c->{'loc'} = $loc;}
}
if ($p->{'interface'} =~ m!local-port!) {
# Local printer
$p->{'interface_args'} =~ m!\"?PORT\"?\s*=\s*\"?([^\"\s]+)\"?!;
my $file = $1;
if (($file =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($file =~ m!^/dev/ptal-printd/(.+)$!) ||
($file =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate device for ptal-printd to ptal URI
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$c->{'connect'} = "ptal:/$devname";
} elsif (($file =~ m!^$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($file =~ m!^/var/mtink/(.+)$!)) {
# Translate device for mtinkd to mtink URI
$c->{'connect'} = "mtink:/$1";
} elsif ($file =~ m!usb!i) {
$c->{'connect'} = "usb:$file";
} elsif ($file =~ m!(tty|serial)!i) {
$c->{'connect'} = "serial:$file";
} elsif ($file =~ m!(lp[0-9]|parallel)!i) {
$c->{'connect'} = "parallel:$file";
} else {
$c->{'connect'} = "file:$file";
}
} elsif ($p->{'interface'} =~ m!bsd-lpd!) {
# Remote LPD
$p->{'interface_args'} =~
m!\"?REMOTE_HOST\"?\s*=\s*\"?([^\"\s]+)\"?!;
my $remhost = $1;
$p->{'interface_args'} =~
m!\"?QUEUE\"?\s*=\s*\"?([^\"\s]+)\"?!;
my $remqueue = $1;
$c->{'connect'} = "lpd://$remhost/$remqueue";
} elsif ($p->{'interface'} =~ m!tcp-port!) {
# Socket
$p->{'interface_args'} =~
m!\"?REMOTE_HOST\"?\s*=\s*\"?([^\"\s]+)\"?!;
my $remhost = $1;
$p->{'interface_args'} =~
m!\"?REMOTE_PORT\"?\s*=\s*\"?([^\"\s]+)\"?!;
my $remport = $1;
$c->{'connect'} = "socket://$remhost:$remport";
}
$dat->{'queuedata'} = $c;
}
if (!defined($dat->{'queuedata'})) {$dat = undef};
return $dat;
}
sub load_ppr_datablob {
my ($queue) = $_[0];
# Load the PPD file
my $ppdfile = sprintf('%s/ppr/%s.ppd',
$sysdeps->{'foo-etc'},
$queue);
my $dat = ppdtoperl($ppdfile);
if (defined($dat)) {
$dat->{'ppdfile'} = $ppdfile;
}
# Get additional info from /etc/ppr/*
my $pconf = load_ppr_printers_conf();
my $p;
for $p (@{$pconf}) {
# were we invoked for only one queue?
next if ($queue ne $p->{'name'});
# Collect values
my $c = {};
$c->{'spooler'} = 'ppr';
$c->{'queue'} = $p->{'name'};
$c->{'foomatic'} = 0;
if (defined($dat->{'id'}) and defined($dat->{'driver'})) {
$c->{'foomatic'} = 1;
$c->{'printer'} = $dat->{'id'};
$c->{'driver'} = $dat->{'driver'};
}
$c->{'desc'} = $p->{'Comment'};
$c->{'loc'} = $p->{'Location'};
if (defined($dat)) {
my @printerdefaults = split('|', $p->{'Switchset'});
my $o;
@{$o->{'options'}} = ();
for my $option (@printerdefaults) {
if (($option =~
/^F\s*\*([^\*\s=:]+)\s+([^\*\s=:]+)\s*$/) ||
($option =~
/^F\s*([^\*\s=:]+)\s*=\s*([^\*\s=:]+)\s*$/)) {
push (@{$o->{'options'}}, "$1=$2");
} elsif (($option =~ /^F\s*\*([^\*\s=:]+)\s*$/) ||
($option =~ /^F\s*([^\*\s=:]+)\s*$/)) {
push (@{$o->{'options'}}, "$1");
}
}
set_default_options($o, $dat);
}
my $address = $p->{'Address'};
my $interface = $p->{'Interface'};
my $interface_options = $p->{'Options'};
if (($interface eq "foomatic-rip") ||
($interface eq "ppromatic")) {
if ($interface_options =~ /backend=(\S+)/) {
$interface = $1;
$interface_options =~ s/backend=(\S+)//;
if ($interface_options =~ /^\s*$/) {
$interface_options = "";
}
} else {
$interface = "";
}
}
my $uri = "";
if (($interface eq "simple") || ($interface eq "parallel") ||
($interface eq "serial") || ($interface eq "dummy")) {
# local printer
if (($address =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($address =~ m!^/dev/ptal-printd/(.+)$!) ||
($address =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate device for ptal-printd to ptal URI
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$uri = "ptal:/$devname";
} elsif (($address =~ m!^$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($address =~ m!^/var/mtink/(.+)$!)) {
# Translate device for mtinkd to mtink URI
$uri = "mtink:/$1";
} elsif ($address =~ m!^\w+:!i) {
$c->{'connect'} = $address;
} else {
$uri = "file:$address";
}
} elsif ($interface eq "lpr") {
# Remote LPD
if ($address =~ /^([^\@]+)\@([^\@]+)$/) {
my $remhost = $2;
my $remqueue = $1;
$uri = "lpd://$remhost/$remqueue";
} else {
die "Remote LPD configuration of the queue $p->{'name'} " .
"broken!\n";
}
} elsif ($interface eq "tcpip") {
# Socket (AppSocket/HP JetDirect)
$uri = "socket://$address";
} elsif ($interface eq "smb") {
# SMB (Printer on Windows server)
if ($address =~ m!^//([^/]+)/([^/]+)$!) {
my $smbserver = $1;
my $smbshare = $2;
my $smbuser = "";
if ($interface_options =~ /smbuser=(\S+)/) {
$smbuser = $1;
} else {
# The PPR interface for SMB uses the user name "ppr"
# when no user name is given.
$smbuser = "ppr";
}
my $smbpassword = "";
if ($interface_options =~ /smbpassword=(\S+)/) {
$smbpassword = $1;
}
if (($smbpassword ne "") && ($smbuser eq "")) {
$smbuser = "GUEST";
}
$uri = "$smbserver/$smbshare";
if ($smbuser ne "") {
if ($smbpassword ne "") {
$smbuser .= ":$smbpassword";
}
$uri = "$smbuser\@$uri";
}
$uri = "smb://$uri";
} else {
die "SMB configuration of the queue $p->{'name'} broken!\n";
}
} else {
# Interface not supported by Foomatic
$uri = "$interface:$address";
}
$c->{'connect'} = $uri;
$dat->{'queuedata'} = $c;
}
if (!defined($dat->{'queuedata'})) {$dat = undef};
return $dat;
}
sub load_direct_datablob {
my ($queue) = $_[0];
# Load the PPD file
my $ppdfile = sprintf('%s/direct/%s.ppd',
$sysdeps->{'foo-etc'},
$queue);
my $dat = ppdtoperl($ppdfile);
if (defined($dat)) {
$dat->{'ppdfile'} = $ppdfile;
}
my $postpipe = (defined($dat) ? $dat->{'postpipe'} : "");
# Get additional info from /etc/foomatic/direct/.config
my $config = load_direct_config();
my $p;
for $p (@{$config}) {
# invalid entry
next if !defined($p->{'name'});
# Search for the correct queue
next if ($queue ne $p->{'name'});
# Collect values
my $c = {};
my $name = $c->{'queue'} = $p->{'name'};
$c->{'desc'} = $p->{'desc'};
$c->{'loc'} = $p->{'loc'};
$c->{'foomatic'} = 0;
if (defined($dat->{'id'}) and defined($dat->{'driver'})) {
$c->{'foomatic'} = 1;
$c->{'printer'} = $dat->{'id'};
$c->{'driver'} = $dat->{'driver'};
}
$c->{'spooler'} = 'direct';
if (defined($postpipe)) {
if ($postpipe =~
m!^\s*\|\s*($sysdeps->{'cat'}|cat)\s+-?\s*>\s*([^\s]+)\s*$!) {
my $file = $2;
if (($file =~ m!^$sysdeps->{'ptal-pipes'}/(.+)$!) ||
($file =~ m!^/dev/ptal-printd/(.+)$!) ||
($file =~ m!^/var/run/ptal-printd/(.+)$!)) {
# Translate device for ptal-printd to ptal URI
my $devname = $1;
$devname =~ s/_/:/;
$devname =~ s/_/:/;
$c->{'connect'} = "ptal:/$devname";
} elsif (($file =~ m!^$sysdeps->{'mtink-pipes'}/(.+)$!) ||
($file =~ m!^/var/mtink/(.+)$!)) {
# Translate device for mtinkd to mtink URI
$c->{'connect'} = "mtink:/$1";
} elsif ($file =~ m!usb!i) {
$c->{'connect'} = "usb:$file";
} elsif ($file =~ m!(tty|serial)!i) {
$c->{'connect'} = "serial:$file";
} elsif ($file =~ m!(lp[0-9]|parallel)!i) {
$c->{'connect'} = "parallel:$file";
} else {
$c->{'connect'} = "file:$file";
}
} elsif ($postpipe =~
m!^\s*\|\s*($sysdeps->{'ptal-connect'}|ptal-connect|ptal-print)\s+(-print\s+|)([^\s]+)(\s+-print|)\s*$!){
$c->{'connect'} = "ptal:/$3";
} elsif ($postpipe =~
m!^\s*\|\s*($sysdeps->{'nc'}|netcat|nc)\s+(-w\s*1\s+|)([^\s]+)\s+([^\s]+)\s*$!){
$c->{'connect'} = "socket://$3:$4";
} elsif ($postpipe =~
m!^\s*\|\s*$sysdeps->{'rlpr'}\s.*-P\s*([^\s\\\@]+)\@([^\s\\\@]+)\s*$!) {
$c->{'connect'} = "lpd://$2/$1";
} elsif ($postpipe =~
m!^.*\|\s*$sysdeps->{'smbclient'}\s+\"//([^/\s]+)/([^/\s]+)\"\s+(\S.*)$!s) {
my $servershare = "$1/$2";
my $parameters = $3;
my $password = "";
if ($parameters =~ m!^([^-]\S*)\s+(\S.*)$!) {
$password = $1;
$parameters = $2;
}
my $username = "";
if ($parameters =~ m!^-U\s+(\S*)\s+(\S.*)$!) {
$username = $1;
$parameters = $2;
}
my $workgroup = "";
if ($parameters =~ m!^-W\s+(\S*)\s+(\S.*)$!) {
$workgroup = "$1/";
}
my $identity = "";
if (($username eq "GUEST") && ($password eq "")) {
$identity = "";
} elsif (($username eq "") && ($password eq "")) {
$identity = "";
} elsif (($username ne "") && ($password eq "")) {
$identity = "$username\@";
} elsif (($username eq "") && ($password ne "")) {
$identity = ":$password\@";
} else {
$identity = "$username:$password\@";
}
$c->{'connect'} = "smb://$identity$workgroup$servershare";
} elsif ($postpipe =~
m!^\s*\|\s*$sysdeps->{'nprint'}\s+(\S.*)$!s) {
my $parameters = $1;
my $server = "";
if ($parameters =~ m!^-S\s+(\S*)\s+(\S.*)$!) {
$server = $1;
$parameters = $2;
}
my $username = "";
if ($parameters =~ m!^-U\s+(\S*)\s+(\S.*)$!) {
$username = $1;
$parameters = $2;
}
my $password = "";
if ($parameters =~ m!^-P\s+(\S*)\s+(\S.*)$!) {
$password = $1;
$parameters = $2;
}
if ($parameters =~ m!^-n\s+(\S.*)$!) {
$parameters = $1;
}
my $queue = "";
if ($parameters =~ m!^-q\s+(\S*)\s+(\S.*)$!) {
$queue = $1;
}
my $identity = "";
if (($username eq "") && ($password eq "")) {
$identity = "";
} elsif (($username ne "") && ($password eq "")) {
$identity = "$username\@";
} elsif (($username eq "") && ($password ne "")) {
$identity = ":$password\@";
} else {
$identity = "$username:$password\@";
}
$c->{'connect'} = "ncp://$identity$server/$queue";
} else {
$postpipe =~ m!\s*\|\s*(\S.*)$!;
$c->{'connect'} = "postpipe:\"$1\"";
}
} else {
$c->{'connect'} = "stdout";
}
$dat->{'queuedata'} = $c;
}
if (!defined($dat->{'queuedata'})) {$dat = undef};
return $dat;
}
sub overtake_defaults {
# overtake the option default settings from $olddatablob
my ($olddatablob) = $_[0];
my $c;
@{$c->{'options'}} = ();
for my $opt (@{$olddatablob->{'args'}}) {
push (@{$c->{'options'}}, "$opt->{'name'}=$opt->{'default'}");
}
set_default_options($c, $db->{'dat'});
}
sub set_default_options {
# Set the default printing options by doing changes on the Perl
# structure produced by "getdat", before the spooler-specific
# datafile is generated
my ($config) = $_[0];
my ($dest) = $_[1];
if ($#{$config->{'options'}} >= 0) {
for (@{$config->{'options'}}) {
my $option = $_;
if ($option =~ m!^\s*([^=]+)=([^=]*)\s*$!) {
# evaluated or numerical option, boolean option with
# value "True", "False", "Yes", "No", "On", "Off", "1", "0"
# given
my $optname = $1;
my $optvalue = $2;
if (defined($dest->{'args_byname'}{$optname})) {
if ($dest->{'args_byname'}{$optname}{'type'} eq
'bool') {
if ((lc($optvalue) eq 'true') ||
(lc($optvalue) eq 'on') ||
(lc($optvalue) eq 'yes')) {
$optvalue = '1';
} elsif ((lc($optvalue) eq 'false') ||
(lc($optvalue) eq 'off') ||
(lc($optvalue) eq 'no')) {
$optvalue = '0';
}
if (($optvalue eq '1') || ($optvalue eq '0')) {
$dest->{'args_byname'}{$optname}{'default'} =
$optvalue;
}
} elsif (($dest->{'args_byname'}{$optname}{'type'} eq
'int') ||
($dest->{'args_byname'}{$optname}{'type'} eq
'float')) {
if (($optvalue =~
m!^\s*[\+\-]?\s*[0-9]*\.?[0-9]*\s*$!) &&
($optvalue >=
$dest->{'args_byname'}{$optname}{'min'}) &&
($optvalue <=
$dest->{'args_byname'}{$optname}{'max'})) {
$dest->{'args_byname'}{$optname}{'default'} =
$optvalue;
}
} elsif (($dest->{'args_byname'}{$optname}{'type'} eq
'string') ||
($dest->{'args_byname'}{$optname}{'type'} eq
'password')) {
$optvalue = Foomatic::DB::checkoptionvalue
($dest, $optname, $optvalue, 0);
$dest->{'args_byname'}{$optname}{'default'} =
$optvalue
if defined($optvalue);
} else {
if (defined($dest->{'args_byname'}{$optname}{'vals_byname'}{$optvalue})) {
$dest->{'args_byname'}{$optname}{'default'} =
$optvalue;
}
}
}
} else {
if (($option =~ /^no(.+?)$/) &&
(defined($dest->{'args_byname'}{$1})) &&
($dest->{'args_byname'}{$1}{'type'} eq
'bool')) {
$dest->{'args_byname'}{$1}{'default'} = '0';
} elsif ((defined($dest->{'args_byname'}{$option})) &&
($dest->{'args_byname'}{$option}{'type'} eq
'bool')) {
$dest->{'args_byname'}{$option}{'default'} = '1';
}
}
}
}
}
sub print_perl_combo_data {
my ($config, $olddatablob) = @_;
# Get the data
if ($config->{'ppdfile'}) {
# From PPD file
my $dat = ppdtoperl($config->{'ppdfile'});
if (!defined($dat)) {
die ("Unable to open PPD file \'$config->{'ppdfile'}\'\n");
}
$db->{'dat'} = $dat;
} else {
# From Foomatic XML database
my $possible = $db->getdat($config->{'driver'},
$config->{'printer'});
die "That printer and driver combination is not possible.\n"
if (!$possible);
die "There is neither a custom PPD file nor the driver database entry contains sufficient data to build a PPD file.\n"
if (!$db->{'dat'}{'cmd'}) && (!$db->{'dat'}{'ppdfile'});
# Generate the PPD and extract it to Perl again (to get in the
# composite options)
my $ppd = $db->getppd($config->{'shortgui'});
delete ($db->{'dat'});
$db->{'dat'} = ppdfromvartoperl([split(/\n/, $ppd)]);
}
# The data can be viewed with the option defaults of an existing
# queue set
if ($olddatablob) {
my $c;
@{$c->{'options'}} = ();
for my $opt (@{$olddatablob->{'args'}}) {
push (@{$c->{'options'}}, "$opt->{'name'}=$opt->{'default'}");
}
set_default_options($c, $db->{'dat'});
}
# User can view the data of the combo also with options given on the
# command line
set_default_options($config, $db->{'dat'});
# Put it out
my $asciidata = $db->getascii();
$asciidata =~ s/\$VAR1/\$COMBODATA/g;
print $asciidata;
return;
}
sub detect_spooler {
# If tcp/localhost:631 opens, cups CUPS is the most sophisticated
# spooler, if it is running, it is usually the primary printing
# system
my $page = ($db->getpage('http://localhost:631/', 1) || "");
if ($page =~ m!Common UNIX Printing System!) {
return 'cups';
}
# PPR is also very sophisticated so check for this spooler if there is
# no CUPS running.
if (-x $sysdeps->{'ppr-ppr'}) {
# There's a /usr/bin/ppr
return 'ppr';
}
# Else if /etc/printcap, some sort of lpd thing
if (-f $sysdeps->{'lpd-pcap'}) {
# If -f /etc/lpd.conf, lprng
if (-f $sysdeps->{'lprng-conf'}) {
return 'lprng';
} elsif (-x $sysdeps->{'lpd-bin'}) {
# There's a /usr/sbin/lpd
return 'lpd';
}
}
# pdq executable in our path somewhere?
for (split(':', $ENV{'PATH'})) {
if (-x "$_/pdq") {
return 'pdq';
}
}
# If there is no known spooler, set up printers for direct, spooler-less
# printing.
return "direct";
}
sub unimp {
die "Sorry, $action for your spooler is unimplemented...\n";
}
sub overview {
print $db->get_overview_xml($opt_f);
exit(0);
}
sub get_xml {
my $x = undef;
if (($opt_p) and ($opt_d)) {
$x = $db->get_combo_data_xml($opt_d,$opt_p);
} elsif ($opt_p) {
$x = $db->get_printer_xml($opt_p);
} elsif ($opt_d) {
$x = $db->get_driver_xml($opt_d);
} else {
die "You must specify a -p printer and/or -d driver.\n";
}
if (defined($x)) {
print $x;
} else {
die "Unable to find object.\n";
}
exit(0);
}
sub help {
print STDERR <<EOH;
Usage: $progname [ -s spooler ] -n queuename \\
[ -N 'Name/Descr.' ] [ -L 'Location Info' ] \\
[ -c connect ] \\
[ -d driver ] [ -p printer ] [ -f ] [ -w ] \\
[ --ppd ppdfile ] \\
[ -o option1=value1 -o option2 ... ] \\
[ --backend-dont-disable=value ] \\
[ --backend-attempts=value ] \\
[ --backend-delay=value ] \\
[ -q ]
or $progname -C [ -s spooler ] -n queuename \\
[ sourcespooler ] sourcequeue \\
[ -N 'Name/Descr.' ] [ -L 'Location Info' ] \\
[ -c connect ] \\
[ -d driver ] [ -p printer ] [ -f ] [ -w ] \\
[ --ppd ppdfile ] \\
[ -o option1=value1 -o option2 ... ] \\
[ --backend-dont-disable=value ] \\
[ --backend-attempts=value ] \\
[ --backend-delay=value ] \\
[ -q ]
or $progname -D [ -s spooler ] -n queuename [ -q ]
or $progname -R [ -s spooler ] -n queuename [ -q ]
or $progname -Q [ -s spooler ] [ -n queuename ] [ -q ] [ -r ]
or $progname -P [ -s spooler ] [ -n queuename ] [ -q ] [ N ]
or $progname -P [ -s spooler ] [ -n queuename ] \\
[ --ppd ppdfile ] [ -d driver -p printer ] \\
[ -o option1=value1 -o option2 ... ] [ -q ]
or $progname -O
or $progname -X [ -p printer ] [ -d driver ]
-n queuename Configure/create/delete/query this print queue
-N Name/Descr. Long name/Short Description. An empty string ("") deletes
the description.
-L Location Short phrase describing this printer's location. An empty
string ("") deletes the location.
-c connection Printer is connected thusly (ex file:/dev/lp0), must
be given when a new queue is created
--ppd ppdfile Set up the queue using the PPD file ppdfile (can be a
manufacturer-supplied PPD file for a PostScript printer).
gzip-compressed PPD files are allowed, they must have the
extension ".gz".
-d driver Foomatic database name for desired printer driver or "raw"
for a raw queue. When a non-raw queue is created, the
printer must be specified in addition ("-p" option)
-p printer Foomatic id for printer. When a non-raw queue is created,
the driver must be specified in addition ("-d" option)
-s spooler Explicit spooler type (cups, lpd, lprng, pdq, ppr, direct)
-o option=value Use value as the default for option in this queue
-o option Set the switch option by default in this queue
--backend-dont-disable=value 1: Do not disable CUPS queue when backend
fails, 0: Original CUPS behaviour, queue gets disabled
when backend fails. Default: 0 (CUPS only)
--backend-attempts=value Try that often when backend fails, for infinite
retries set the value to zero, for standard CUPS
behaviour to 1. Default: 1 (CUPS only)
--backend-delay=value Delay in seconds between retries of failed backend.
Default: 30 (CUPS only)
-C [sourcespooler] sourcequeue Create a copy of a queue. All
characteristics including default option settings are
overtaken. Additional arguments modify the copy. This
facility allows to overtake one's configured queues when
one changes the spooler.
-D Set this queue as the queue used by default.
-R Remove this whole queue entirely (just give -n queuename)
-Q Query existing configuration (gives XML summary). Supplying
no queue name gives info about all installed queues for the
current/selected spooler, including the default queue.
-r list also remote queues (CUPS only).
-P Query existing configuration (gives Perl data structure of
the complete information about the queue, including
options, possible choices, default settings, ..., for use
by frontends, the output is done as a Perl array, one
element per queue), With printer ID and driver name instead
of queue name supplied the Perl data structure of the
appropriate printer/driver combo is generated, supplied
options are entered as default settings then, from a
supplied queue the option default settings are used.
Supplying no queue, printer, and driver gives info about
all installed queues for the current/selected spooler.
N The first index of the Perl array, default: 0
-O Print XML Overview of all known printer/drivers
-X Print XML data for -p printer and/or -d driver object
-f Force rebuild of PPD file from database
-w Generate PPD which is compatible to the CUPS PostScript
driver for Windows (GUI strings are limited to 39 characters).
This applies only to PPDs built from the Foomatic database, it
has no influence on PPDs supplied with the "--ppd" option.
-q Run quietly and non-interactive
-h --help Show this help message
EOH
#'# Fix emacs syntax highlighting
exit 0;
}